diff options
author | Martin Odersky <odersky@gmail.com> | 2005-02-04 13:04:57 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2005-02-04 13:04:57 +0000 |
commit | 4ab12055ef6a548afdf1b9d583c291b74d3630bc (patch) | |
tree | f678ed874115f2654a7ec0398ddf027c0803a707 /sources | |
parent | 204dbd6dacd0bd3c16c3266b98673e4a630932ce (diff) | |
download | scala-4ab12055ef6a548afdf1b9d583c291b74d3630bc.tar.gz scala-4ab12055ef6a548afdf1b9d583c291b74d3630bc.tar.bz2 scala-4ab12055ef6a548afdf1b9d583c291b74d3630bc.zip |
*** empty log message ***
Diffstat (limited to 'sources')
41 files changed, 12251 insertions, 3 deletions
diff --git a/sources/scala/tools/nsc/CompilationUnits.scala b/sources/scala/tools/nsc/CompilationUnits.scala new file mode 100644 index 0000000000..303f4dcdfd --- /dev/null +++ b/sources/scala/tools/nsc/CompilationUnits.scala @@ -0,0 +1,27 @@ +package scala.tools.nsc; + +import scala.tools.util.{SourceFile, Position}; +import scala.tools.nsc.util.FreshNameCreator; + +class CompilationUnits: Global { + + class CompilationUnit(val source: SourceFile, val mixinOnly: boolean) { + + /** short constructor */ + def this(source: SourceFile) = this(source, false); + + /** the fresh name creator */ + val fresh = new FreshNameCreator; + + /** the content of the compilation unit in tree form */ + var body: List[Tree] = List(); + + def position(pos: int) = new Position(source, pos); + + def error(pos: int, msg: String) = reporter.error(position(pos), msg); + def warning(pos: int, msg: String) = reporter.warning(position(pos), msg); + override def toString() = source.toString(); + } +} + + diff --git a/sources/scala/tools/nsc/CompilerCommand.scala b/sources/scala/tools/nsc/CompilerCommand.scala new file mode 100644 index 0000000000..3d7b048292 --- /dev/null +++ b/sources/scala/tools/nsc/CompilerCommand.scala @@ -0,0 +1,56 @@ +package scala.tools.nsc; + +import scala.tools.util.Reporter; + +/** A class representing command line info for scalac */ +class CompilerCommand(arguments: Array[String], error: String => unit) { + private var fs: List[String] = List(); + + /** All files to compile */ + def files: List[String] = fs.reverse; + + /** The applicable settings */ + val settings: Settings = new Settings(error); + + /** A message explaining usage and options */ + def usageMsg: String = { + val helpSyntaxColumnWidth: int = + Iterable.max(settings.allSettings map (. helpSyntax.length())); + def format(s: String): String = { + val buf = new StringBuffer(); + buf.append(s); + var i = s.length(); + while (i < helpSyntaxColumnWidth) { buf.append(' '); i = i + 1 } + buf.toString() + } + settings.allSettings + .map(setting => + format(setting.helpSyntax) + " " + setting.helpDescription) + .mkString( + "Usage: scalac <options | source files>\n" + + "where possible options include: \n", + "\n ", + "\n"); + } + + // initialization + var args = List.fromArray(arguments); + var ok = true; + while (!args.isEmpty && ok) { + val args0 = args; + if (args.head.startsWith("-")) { + for (val setting <- settings.allSettings) + args = setting.tryToSet(args); + if (args eq args0) { + error("unknown option: '" + args.head + "'"); + ok = false + } + } else if (args.head.endsWith(".scala")) { + fs = args.head :: fs; + args = args.tail + } else { + error("don't know what to do with " + args.head); + ok = false + } + } +} diff --git a/sources/scala/tools/nsc/FatalError.scala b/sources/scala/tools/nsc/FatalError.scala new file mode 100755 index 0000000000..6a139069d6 --- /dev/null +++ b/sources/scala/tools/nsc/FatalError.scala @@ -0,0 +1,3 @@ +package scala.tools.nsc; + +case class FatalError(msg: String) extends Exception; diff --git a/sources/scala/tools/nsc/Global.scala b/sources/scala/tools/nsc/Global.scala new file mode 100755 index 0000000000..6e786f5b29 --- /dev/null +++ b/sources/scala/tools/nsc/Global.scala @@ -0,0 +1,202 @@ +package scala.tools.nsc; + +import java.io._; +import java.nio.charset._; +import scala.tools.util._; +import scala.collection.mutable.{HashSet,HashMap,ListBuffer} + +import symtab._; +import symtab.classfile.Pickle; +import util._; +import ast._; +import ast.parser._; + +class Global(val settings: Settings, val reporter: Reporter) + extends SymbolTable + with Trees + with CompilationUnits { + +// sub-components -------------------------------------------------- + + object treePrinters extends TreePrinters { + val global: Global.this.type = Global.this + } + val treePrinter = treePrinters.create(); + + object treeInfo extends TreeInfo { + val global: Global.this.type = Global.this + } + +// reporting ------------------------------------------------------- + + def informTime(msg: String, start: long) = { + val end = System.currentTimeMillis(); + reporter.info(null, "[" + msg + " in " + (end - start) + "ms]", false); + } + + def error(msg: String) = reporter.error(null, msg); + def warning(msg: String) = reporter.warning(null, msg); + def inform(msg: String) = reporter.info(null, msg, true); + + def log(msg: String) = + if (settings.log contains phase.name) inform("[log " + phase + "] " + msg); + +// file interface ------------------------------------------------------- + + private val reader: SourceReader = { + def stdCharset: Charset = { + settings.encoding.value = "ISO-8859-1"; // A mandatory charset + Charset.forName(settings.encoding.value); + } + val charset = + try { + Charset.forName(settings.encoding.value); + } catch { + case _: IllegalCharsetNameException => + error("illegal charset name '" + settings.encoding.value + "'"); + stdCharset + case _: UnsupportedCharsetException => + error("unsupported charset '" + settings.encoding.value + "'"); + stdCharset + } + new SourceReader(charset.newDecoder()); + } + + val classPath = new ClassPath( + settings.classpath.value, + settings.sourcepath.value, + settings.bootclasspath.value, + settings.extdirs.value); + + if (settings.verbose.value) { + System.out.println("classpath = " + classPath); + } + + def getSourceFile(f: AbstractFile): SourceFile = + new SourceFile(f, reader.read(f)); + + def getSourceFile(name: String): SourceFile = { + val f = AbstractFile.getFile(name); + if (f == null) throw new FileNotFoundException( + "source file '" + name + "' could not be found"); + getSourceFile(f) + } + + def getSourceFile(clazz: Symbol): SourceFile = { + val f = classPath.getRoot().lookupPath( + clazz.fullNameString(File.separatorChar) + ".scala", false); + if (f == null) throw new FileNotFoundException( + "source file for " + clazz + " could not be found"); + getSourceFile(f) + } + + private object loaders extends SymbolLoaders { + val global: Global.this.type = Global.this + } + + def rootLoader: LazyType = loaders.packageLoader(classPath.getRoot()); + +// Phases ------------------------------------------------------------ + + object parserPhase extends ParserPhase(NoPhase) { + val global: Global.this.type = Global.this + } + val analyzerPhase = new StdPhase(parserPhase) { + def name = "analyzer"; + val global: Global.this.type = Global.this; + def apply(unit: CompilationUnit): unit = {} + } + + val terminalPhase = new StdPhase(analyzerPhase) { + def name = "terminal"; + val global: Global.this.type = Global.this; + def apply(unit: CompilationUnit): unit = {} + } + + definitions.init; + +// Units and how to compile them ------------------------------------- + + private var unitbuf = new ListBuffer[CompilationUnit]; + private var fileset = new HashSet[AbstractFile]; + + private def addUnit(unit: CompilationUnit): unit = { + unitbuf += unit; + fileset += unit.source.getFile(); + } + + def units: Seq[CompilationUnit] = unitbuf; + + /** A map from compiled top-level symbols to their source files */ + val symSource = new HashMap[Symbol, AbstractFile]; + + /** A map from compiled top-level symbols to their picklers */ + val symData = new HashMap[Symbol, Pickle]; + + def compileSources(sources: List[SourceFile]): unit = { + val startTime = System.currentTimeMillis(); + unitbuf.clear; + fileset.clear; + symSource.clear; + symData.clear; + reporter.resetCounters(); + for (val source <- sources) + addUnit(new CompilationUnit(source)); + phase = NoPhase.next; + while (phase != terminalPhase && reporter.errors() == 0) { + val startTime = System.currentTimeMillis(); + if (!(settings.skip contains phase.name)) phase.run; + if (settings.print contains phase.name) treePrinter.printAll(); + informTime(phase.description, startTime); + phase = if (settings.stop contains phase.name) terminalPhase else phase.next; + } + if (settings.Xshowcls.value != "") showDef(newTermName(settings.Xshowcls.value), false); + if (settings.Xshowobj.value != "") showDef(newTermName(settings.Xshowobj.value), true); + + if (reporter.errors() != 0) + for (val Pair(sym, file) <- symSource.elements) + sym.reset(loaders.sourcefileLoader(file)); + informTime("total", startTime); + } + + def compileLate(file: AbstractFile, mixinOnly: boolean): unit = { + if (!(fileset contains file)) { + val unit = new CompilationUnit(getSourceFile(file), mixinOnly); + addUnit(unit); + atPhase(parserPhase) { parserPhase.apply(unit) } + //atPhase(analyzerPhase) { analyzerPhase.lateEnter(unit) } + } + } + + def compileFiles(files: List[AbstractFile]): unit = + try { + compileSources(files map getSourceFile) + } catch { + case ex: IOException => error(ex.getMessage()); + } + + def compile(filenames: List[String]): unit = + try { + compileSources(filenames map getSourceFile) + } catch { + case ex: IOException => error(ex.getMessage()); + } + + def showDef(name: Name, module: boolean): unit = { + def getSym(name: Name, module: boolean): Symbol = { + var i = name.length - 1; + while (i != 0 && name(i) != '#' && name(i) != '.') i = i - 1; + if (i == 0) + definitions.getModule(name) + else { + val root = getSym(name.subName(0, i), name(i) == '.'); + var selector = name.subName(i+1, name.length); + if (module) selector = selector.toTypeName; + root.info.lookup(selector) + } + } + val sym = getSym(name, module); + System.err.println("" + sym.name + ":" + + (if (module) sym.moduleClass.info else sym.info)) + } +} diff --git a/sources/scala/tools/nsc/Main.scala b/sources/scala/tools/nsc/Main.scala new file mode 100755 index 0000000000..8265c58843 --- /dev/null +++ b/sources/scala/tools/nsc/Main.scala @@ -0,0 +1,48 @@ +package scala.tools.nsc; + +import scala.tools.util.{Position, Reporter, ConsoleReporter} + +/** The main class for NSC, a compiler for the programming + * language Scala. + */ +object Main { + + val PRODUCT: String = + System.getProperty("scala.product", "scalac"); + val VERSION: String = + System.getProperty("scala.version", "unknown version"); + val versionMsg = PRODUCT + " " + VERSION + " -- (c) 2002-04 LAMP/EPFL"; + + private var reporter: Reporter = _; + + def error(msg: String): unit = + reporter.error(new Position(PRODUCT), + msg + "\n " + PRODUCT + " -help gives more information"); + + def process(args: Array[String]): unit = { + reporter = new ConsoleReporter(); + val command = new CompilerCommand(args, error); + reporter.prompt(command.settings.prompt.value); + if (command.settings.version.value) + reporter.info(null, versionMsg, true) + else if (command.settings.help.value || command.files.isEmpty) + reporter.info(null, command.usageMsg, true) + else { + try { + val compiler = new Global(command.settings, reporter); + compiler.compile(command.files); + } catch { + case ex @ FatalError(msg) => + if (command.settings.debug.value) + ex.printStackTrace(); + System.out.println("fatal error: " + msg); + } + reporter.printSummary + } + } + + def main(args: Array[String]): unit = { + process(args); + System.exit(if (reporter.errors() > 0) 1 else 0); + } +} diff --git a/sources/scala/tools/nsc/NoPhase.scala b/sources/scala/tools/nsc/NoPhase.scala new file mode 100644 index 0000000000..f9685f8010 --- /dev/null +++ b/sources/scala/tools/nsc/NoPhase.scala @@ -0,0 +1,6 @@ +package scala.tools.nsc; + +object NoPhase extends Phase(null) { + def name = "<no phase>"; + def run: unit = throw new Error("NoPhase.run"); +} diff --git a/sources/scala/tools/nsc/Phase.scala b/sources/scala/tools/nsc/Phase.scala new file mode 100644 index 0000000000..cd6034d29e --- /dev/null +++ b/sources/scala/tools/nsc/Phase.scala @@ -0,0 +1,26 @@ +package scala.tools.nsc; + +abstract class Phase(val prev: Phase) { + val id: int = if (prev == null) 0 else prev.id + 1; + + private var nx: Phase = NoPhase; + if (prev != null) prev.nx = this; + + def next: Phase = nx; + + def name: String; + def description: String = name; + + val flagMask: long = if (prev == null) 0L else prev.flagMask; + def exactMatch: boolean = false; + + def run: unit; + + override def toString() = name; + + // def check(units: List[CompilationUnit]): unit = + // for (val unit <- units; val checker <- checkers) checker.traverse(unit); // def checkers: List[Checker] = List(); + +} + + diff --git a/sources/scala/tools/nsc/Settings.scala b/sources/scala/tools/nsc/Settings.scala new file mode 100644 index 0000000000..7820f0adcb --- /dev/null +++ b/sources/scala/tools/nsc/Settings.scala @@ -0,0 +1,155 @@ +package scala.tools.nsc; + +class Settings(error: String => unit) { + + private var allsettings: List[Setting] = List(); + + val debuginfo = BooleanSetting("-g", "Generate debugging info"); + val nowarnings = BooleanSetting("-nowarn", "Generate no warnings"); + val verbose = BooleanSetting("-verbose", "Output messages about what the compiler is doing"); + val classpath = StringSetting ("-classpath", "path", "Specify where to find user class files", + System.getProperty("scala.class.path", + System.getProperty("java.class.path", "."))); + val sourcepath = StringSetting ("-sourcepath", "path", "Specify where to find input source files", + System.getProperty("scala.source.path", + System.getProperty("java.source.path", "."))); + val bootclasspath = StringSetting ("-bootclasspath", "path", "Override location of bootstrap class files", + System.getProperty("sun.boot.class.path", "")); + val extdirs = StringSetting ("-extdirs", "dirs", "Override location of installed extensions", + System.getProperty("java.ext.dirs", "")); + val outdir = StringSetting ("-d", "directory", "Specify where to place generated class files", "."); + val encoding = StringSetting ("-encoding", "encoding", "Specify character encoding used by source files", "ISO-8859-1"); + val separate = ChoiceSetting ("-separate", "Read symbol files for separate compilation", List("yes","no"), "default"); + val target = ChoiceSetting ("-target", "Specify which backend to use", List("jvm", "msil"), "jvm"); + val debug = BooleanSetting("-debug", "Output debugging messages"); + val explaintypes = BooleanSetting("-explaintypes", "Explain type errors in more detail"); + val uniqid = BooleanSetting("-uniqid", "Print identifiers with unique names (debugging option)"); + val printtypes = BooleanSetting("-printtypes", "Print tree types (debugging option)"); + val prompt = BooleanSetting("-prompt", "Display a prompt after each error (debugging option)"); + val noimports = BooleanSetting("-noimports", "Compile without any implicit imports"); + val nopredefs = BooleanSetting("-nopredefs", "Compile without any implicit predefined values"); + val skip = PhasesSetting ("-skip", "Skip"); + val check = PhasesSetting ("-check", "Check the tree after"); + val print = PhasesSetting ("-print", "Print out program after"); + val printer = ChoiceSetting ("-printer", "Printer to use", List("text", "html"), "text"); + val printfile = StringSetting ("-printfile", "file", "Specify file in which to print trees", "-"); + val graph = PhasesSetting ("-graph", "Graph the program after"); + val stop = PhasesSetting ("-stop", "Stop after first phase in"); + val log = PhasesSetting ("-log", "Log operations in"); + val version = BooleanSetting("-version", "Print product version and exit"); + val help = BooleanSetting("-help", "Print a synopsis of standard options"); + + val Xshowcls = StringSetting ("-Xshowcls", "class", "Show class info", ""); + val Xshowobj = StringSetting ("-Xshowobj", "object", "Show object info", ""); + + /** A list of all settings */ + def allSettings: List[Setting] = allsettings.reverse; + + /** A base class for settings of all types. + * Subclasses each define a `value' field of the appropriate type. + */ + abstract class Setting(name: String, descr: String) { + + /** If first arg defines this setting, consume it as well as all following + * args needed to define the setting. If this can be done without + * error, set value field and return suffix of args else + * issue error message and return empty. + * If first arg does not define this setting return args unchanged. + */ + def tryToSet(args: List[String]): List[String]; + + /** The syntax defining this setting in a help string */ + def helpSyntax: String = name; + + /** A description of the purpose of this setting in a help string */ + def helpDescription = descr; + + // initialization + allsettings = this :: allsettings; + } + + /** A setting represented by a boolean flag (false, unless set */ + case class BooleanSetting(name: String, descr: String) + extends Setting(name, descr) { + var value: boolean = false; + + def tryToSet(args: List[String]): List[String] = args match { + case n :: rest if (n == name) => value = true; rest + case _ => args + } + } + + /** A setting represented by a string, (`default' unless set) */ + case class StringSetting(name: String, arg: String, descr: String, default: String) + extends Setting(name, descr) { + var value: String = default; + + def tryToSet(args: List[String]): List[String] = args match { + case n :: rest if (n == name) => + if (rest.isEmpty) { + error("missing argument"); + List() + } else { + value = rest.head; + rest.tail + } + case _ => args + } + + override def helpSyntax = name + " <" + arg + ">"; + } + + /** A setting represented by a string in a given set of `choices', + * (`default' unless set) + */ + case class ChoiceSetting(name: String, descr: String, choices: List[String], default: String) + extends Setting(name, descr + choices.mkString(" (", ",", ")")) { + var value: String = default; + + private def argument: String = name.substring(1); + + def tryToSet(args: List[String]): List[String] = args match { + case n :: rest if (n startsWith (name + ":")) => + val choice = n.substring(name.length() + 1); + if (!(choices contains choice)) { + error( + if (choice == "") "missing " + argument + else "unknown " + argument + " '" + choice + "'"); + List() + } else { + value = choice; + rest + } + case _ => args + } + + override def helpSyntax = name + ":<" + argument + ">"; + } + + /** A setting represented by a list of strings which should be prefixes of + * phase names. This is not checked here, however. + * (the empty list, unless set) + */ + case class PhasesSetting(name: String, descr: String) + extends Setting(name, descr + " <phases> (see below)") { + var value: List[String] = List(); + + def tryToSet(args: List[String]): List[String] = args match { + case n :: rest if (n startsWith (name + ":")) => + val phase = n.substring(name.length() + 1); + if (phase == "") { + error("missing phase"); + List() + } else { + value = value ::: List(phase); + rest + } + case _ => args + } + + override def helpSyntax = name + ":<phases>"; + + def contains(phasename: String): boolean = + value exists (str => phasename startsWith str) + } +} diff --git a/sources/scala/tools/nsc/StdPhase.scala b/sources/scala/tools/nsc/StdPhase.scala new file mode 100644 index 0000000000..46f4d296f4 --- /dev/null +++ b/sources/scala/tools/nsc/StdPhase.scala @@ -0,0 +1,10 @@ +package scala.tools.nsc; + +abstract class StdPhase(prev: Phase) extends Phase(prev) { + val global: Global; + def run: unit = + for (val unit <- global.units) apply(unit); + def apply(unit: global.CompilationUnit): unit; +} + + diff --git a/sources/scala/tools/nsc/ast/TreeInfo.scala b/sources/scala/tools/nsc/ast/TreeInfo.scala new file mode 100644 index 0000000000..9b79027abc --- /dev/null +++ b/sources/scala/tools/nsc/ast/TreeInfo.scala @@ -0,0 +1,136 @@ +package scala.tools.nsc.ast; + +import symtab.Flags._; + +abstract class TreeInfo { + + val global: Global; + import global._; + + def isTerm(tree: Tree): boolean = tree.isTerm; + def isType(tree: Tree): boolean = tree.isType; + + def isOwnerDefinition(tree: Tree): boolean = tree match { + case PackageDef(_, _) + | ClassDef(_, _, _, _, _, _) + | ModuleDef(_, _, _, _) + | DefDef(_, _, _, _, _, _) + | Import(_, _) => true + case _ => false + } + + def isDefinition(tree: Tree): boolean = tree.isDef; + + def isDeclaration(tree: Tree): boolean = tree match { + case DefDef(_, _, _, _, _, EmptyTree) + | ValDef(_, _, _, EmptyTree) + | AbsTypeDef(_, _, _, _, _) + | AliasTypeDef(_, _, _, _) => true + case _ => false + } + + /** Is tree a pure definition? + */ + def isPureDef(tree: Tree): boolean = tree match { + case EmptyTree + | ClassDef(_, _, _, _, _, _) + | ModuleDef(_, _, _, _) + | AbsTypeDef(_, _, _, _, _) + | AliasTypeDef(_, _, _, _) + | Import(_, _) + | DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => + true + case ValDef(mods, _, _, rhs) => + (mods & MUTABLE) == 0 && isPureExpr(rhs) + case DocDef(_, definition) => + isPureDef(definition) + case _ => + false + } + + /** Is tree a stable & pure expression? + */ + def isPureExpr(tree: Tree): boolean = tree match { + case EmptyTree + | This(_) + | Super(_, _) + | Literal(_) => + true + case Ident(_) => + tree.symbol.isStable + case Select(qual, _) => + tree.symbol.isStable && isPureExpr(qual) + case TypeApply(fn, _) => + isPureExpr(fn) + case Apply(fn, List()) => + isPureExpr(fn) + case Typed(expr, _) => + isPureExpr(expr) + case _ => + false + } + + /** Is tree a pure constructor? + */ + def isPureConstr(tree: Tree): boolean = tree match { + case Ident(_) + | Select(_, _) => + tree.symbol != null && tree.symbol.isPrimaryConstructor; + case TypeApply(fn, _) => + isPureConstr(fn) + case Apply(fn, List()) => + isPureConstr(fn) + case _ => + false + } + + /** Is tree a self constructor call? + */ + def isSelfConstrCall(tree: Tree): boolean = tree match { + case Ident(nme.CONSTRUCTOR) => + true + case TypeApply(constr, _) => + isSelfConstrCall(constr) + case Apply(constr, _) => + isSelfConstrCall(constr) + case _ => + false + } + + /** Is tree a variable pattern */ + def isVarPattern(pat: Tree): boolean = pat match { + case Ident(name) => isVariableName(name) + case _ => false + } + + /** Is name a variable name */ + def isVariableName(name: Name): boolean = { + val first = name(0); + (('a' <= first && first <= 'z') || first == '_') + && name != nme.false_ + && name != nme.true_ + && name != nme.null_ + } + + /** Is tree a this node which belongs to `enclClass'? */ + def isSelf(tree: Tree, enclClass: Symbol): boolean = tree match { + case This(_) => tree.symbol == enclClass + case _ => false + } + + /** The method symbol of an application node, or NoSymbol, if none exists. + */ + def methSymbol(tree: Tree): Symbol = { + val meth = methPart(tree); + if (meth.hasSymbol) meth.symbol else NoSymbol + } + + /** The method part of an application node + */ + def methPart(tree: Tree): Tree = tree match { + case Apply(fn, _) => methPart(fn) + case TypeApply(fn, _) => methPart(fn) + case AppliedTypeTree(fn, _) => methPart(fn) + case _ => tree + } +} diff --git a/sources/scala/tools/nsc/ast/TreePrinters.scala b/sources/scala/tools/nsc/ast/TreePrinters.scala new file mode 100644 index 0000000000..329bed60d7 --- /dev/null +++ b/sources/scala/tools/nsc/ast/TreePrinters.scala @@ -0,0 +1,293 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id: TreePrinter.scala + +package scala.tools.nsc.ast; + +import java.io._; +import symtab.Flags._; + +abstract class TreePrinters { + + val global: Global; + import global._; + + class TreePrinter(out: PrintWriter) { + protected var indentMargin = 0; + protected val indentStep = 2; + protected var indentString = " "; + + def flush = out.flush(); + + def indent = indentMargin = indentMargin + indentStep; + def undent = indentMargin = indentMargin - indentStep; + + def println = { + out.println(); + while (indentMargin > indentString.length()) + indentString = indentString + indentString; + if (indentMargin > 0) + out.write(indentString, 0, indentMargin); + } + + def printSeq[a](ls: List[a])(printelem: a => unit)(printsep: => unit): unit = ls match { + case List() => + case List(x) => printelem(x) + case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep) + } + + def printColumn(ts: List[Tree], start: String, sep: String, end: String): unit = { + print(start); indent; println; + printSeq(ts){print}{print(sep); println}; undent; println; print(end) + } + + def printRow(ts: List[Tree], start: String, sep: String, end: String): unit = { + print(start); printSeq(ts){print}{print(sep)}; print(end) + } + + def printRow(ts: List[Tree], sep: String): unit = printRow(ts, "", sep, ""); + + def printTypeParams(ts: List[AbsTypeDef]): unit = + if (!ts.isEmpty) { + print("["); printSeq(ts){printParam}{print(", ")}; print("]") + } + + def printValueParams(ts: List[ValDef]): unit = + if (!ts.isEmpty) { + print("("); printSeq(ts){printParam}{print(", ")}; print(")") + } + + def printParam(tree: Tree): unit = tree match { + case ValDef(mods, name, tp, rhs) => + if ((mods & PARAMACCESSOR) != 0) { + print(tree) + } else { + print(symName(tree, name)); printOpt(": ", tp); + } + case AbsTypeDef(mods, name, lo, hi, vu) => + print(symName(tree, name)); + printOpt(">: ", lo); printOpt("<: ", hi); printOpt("<% ", vu) + } + + def symName(tree: Tree, name: Name): String = + if (tree.symbol != null && tree.symbol != NoSymbol) tree.symbol.nameString + else name.toString(); + + def printOpt(prefix: String, tree: Tree): unit = + if (tree != EmptyTree) { print(prefix); print(tree) } + + def printModifiers(flags: int): unit = { + val s = flagsToString(flags); + if (s.length() != 0) print(s + " ") + } + + def print(str: String): unit = out.print(str); + def print(name: Name): unit = print(name.toString()); + + def print(tree: Tree): unit = { + tree match { + case EmptyTree => + print("<empty>"); + + case ClassDef(mods, name, tparams, vparams, tp, impl) => + printModifiers(mods); print("class " + symName(tree, name)); + printTypeParams(tparams); vparams foreach printValueParams; + printOpt(": ", tp); print(" extends "); print(impl); + + case PackageDef(packaged, stats) => + print("package "); print(packaged); printColumn(stats, " {", ";", "}") + + case ModuleDef(mods, name, tpe, impl) => + printModifiers(mods); print("object " + symName(tree, name)); + printOpt(": ", tpe); print(" extends "); print(impl); + + case ValDef(mods, name, tp, rhs) => + printModifiers(mods); + print(if ((mods & MUTABLE) != 0) "var " else "val "); + print(symName(tree, name)); + printOpt(": ", tp); + if ((mods & DEFERRED) == 0) { + print(" = "); + if (rhs == EmptyTree) print("_") else print(rhs) + } + + case DefDef(mods, name, tparams, vparams, tp, rhs) => + printModifiers(mods); + print("def " + (if (name == nme.CONSTRUCTOR) "this" else symName(tree, name))); + printTypeParams(tparams); vparams foreach printValueParams; + printOpt(": ", tp); printOpt(" = ", rhs); + + case AbsTypeDef(mods, name, lo, hi, vu) => + printModifiers(mods); print("type "); printParam(tree); + + case AliasTypeDef(mods, name, tparams, rhs) => + printModifiers(mods); print("type " + symName(tree, name)); + printTypeParams(tparams); printOpt(" = ", rhs); + + case LabelDef(name, params, rhs) => + print(symName(tree, name)); printRow(params, "(", ",", ")"); print(rhs); + + case Import(expr, selectors) => + def printSelectors(ss: List[Name]): unit = ss match { + case List() => + case List(s) => print(s.toString()); + case s1 :: s2 :: ss1 => + print(s1); + if (s1 != s2) print("=>" + s2); + printSelectors(ss1); + } + print("import "); print(expr); print(".{"); printSelectors(selectors); print("}"); + + case PatDef(mods, pat, rhs) => + print(flagsToString(mods) + " val "); print(pat); printOpt(" = ", rhs); + + case Attributed(attr, definition) => + print("["); print(attr); print("]"); println; print(definition); + + case DocDef(comment, definition) => + print(comment); println; print(definition); + + case Template(parents, body) => + printRow(parents, " with "); printColumn(body, " {", ";", "}"); + + case Block(stats, expr) => + printColumn(stats ::: List(expr), "{", ";", "}") + + case Visitor(cases) => + printColumn(cases, "{", "", "}"); + + case CaseDef(pat, guard, body) => + print("case "); print(pat); printOpt(" if ", guard); + print(" => "); print(body) + + case Sequence(trees) => + printRow(trees, "[", ", ", "]") + + case Alternative(trees) => + printRow(trees, "(", "| ", ")") + + case Bind(name, t) => + print(symName(tree, name)); print(" @ "); print(t) + + case Function(vparams, body) => + print("("); printValueParams(vparams); print(" => "); print(body); print(")") + + case Assign(lhs, rhs) => + print(lhs); print(" = "); print(rhs) + + case For(enumerators, body, isForYield) => + printRow(enumerators, "for(", "; ", ") "); + if (isForYield) print("yield "); + print(body) + + case If(cond, thenp, elsep) => + print("if ("); print(cond); print(")"); indent; println; + print(thenp); undent; + if (elsep != EmptyTree) { + println; print("else"); indent; println; print(elsep); undent + } + + case Switch(expr, tags, bodies, defaultBody) => + print("<switch> ("); print(expr); print(") {"); indent; + printSeq(tags zip bodies) + {case Pair(tag, body) => print("case " + tag + " => "); print(body)} {println} + print("<default> => "); print(defaultBody); print(" }"); undent + + case Return(expr) => + print("return "); print(expr) + + case Try(block, catcher, finalizer) => + print("try "); print(block); print(" catch "); print(catcher); + print(" finally "); print(finalizer) + + case Throw(expr) => + print("throw "); print(expr) + + case New(init) => + print("new "); print(init) + + case Typed(expr, tp) => + print("("); print(expr); print(") : "); print(tp); + + case TypeApply(fun, targs) => + print(fun); printRow(targs, "[", ", ", "]"); + + case Apply(fun, vargs) => + print(fun); printRow(vargs, "(", ", ", ")"); + + case Super(qual, mixin) => + if (qual != nme.EMPTY.toTypeName) print(symName(tree, qual) + "."); + print("super"); + if (mixin != nme.EMPTY.toTypeName) print("[" + mixin + "]") + + case This(qual) => + if (qual != nme.EMPTY.toTypeName) print(symName(tree, qual) + "."); + print("this"); + + case Select(qualifier, name) => + if (global.settings.debug.value || qualifier.symbol == null || !qualifier.symbol.isRoot) { + print(qualifier); print("."); + } + print(symName(tree, name)) + + case Ident(name) => + print(symName(tree, name)) + + case Literal(obj) => + print(obj match { + case null => "null" + case s: String => "\"" + s + "\"" + case _ => obj.toString() + }) + + case GeneralTypeTree() => + print(tree.tpe.toString()); + + case SingletonTypeTree(ref) => + print(ref); print(".type") + + case SelectFromTypeTree(qualifier, selector) => + print(qualifier); print("#"); print(symName(tree, selector)) + + case FunctionTypeTree(argtpes, restpe) => + printRow(argtpes, "(", ", ", ") => "); print(restpe) + + case IntersectionTypeTree(parents) => + printRow(parents, " with ") + + case RefinementTypeTree(base, members) => + print(base); printColumn(members, "{", ";", "}") + + case AppliedTypeTree(tp, args) => + print(tp); printRow(args, "[", ", ", "]") + } + if (global.settings.printtypes.value && tree.isTerm && tree != EmptyTree) { + print("{"); print(if (tree.tpe == null) "<null>" else tree.tpe.toString()); print("}") + } + } + + def print(unit: CompilationUnit): unit = { + print("// Scala source: " + unit.source + "\n"); + if (unit.body != null) { + unit.body foreach { tree => print(tree); print(";"); println } + } else { + print("<null>") + } + println; flush + } + + def printAll(): unit = { + print("[[syntax trees at end of " + phase + "]]"); + for (val unit <- global.units) print(unit) + } + } + + def create(writer: PrintWriter): TreePrinter = new TreePrinter(writer); + def create(stream: OutputStream): TreePrinter = create(new PrintWriter(stream)); + def create(): TreePrinter = create(System.out); +} diff --git a/sources/scala/tools/nsc/ast/Trees.scala b/sources/scala/tools/nsc/ast/Trees.scala new file mode 100644 index 0000000000..4cfa348e77 --- /dev/null +++ b/sources/scala/tools/nsc/ast/Trees.scala @@ -0,0 +1,865 @@ +package scala.tools.nsc.ast; + +import java.io.StringWriter; +import java.io.PrintWriter; +import scala.tools.util.Position; + +class Trees: Global { + + abstract class Tree { + + var pos: int = Position.NOPOS; + var tpe: Type = _; + + def setPos(p: int): Tree = { pos = p; this } + def setType(tp: Type): Tree = { tpe = tp; this } + + def symbol: Symbol = null; + def symbol_=(sym: Symbol): unit = + throw new Error("symbol_= inapplicable for " + this); + def setSymbol(sym: Symbol): Tree = { symbol = sym; this } + + def hasSymbol = false; + def isDef = false; + def isTerm = false; + def isType = false; + + override def toString(): String = { + val buffer = new StringWriter(); + val printer = treePrinters.create(new PrintWriter(buffer)); + printer.print(this); printer.flush; + buffer.toString() + } + + def duplicate: Tree = + new Transformer(new StrictTreeCopier) transform this; + } + + abstract class SymTree extends Tree { + override def hasSymbol = true; + override var symbol: Symbol = NoSymbol; + } + + abstract class DefTree extends SymTree { + override def isDef = true; + } + + abstract class TermTree extends Tree { + override def isTerm = true; + } + + abstract class TypeTree extends Tree { + override def isType = true; + } + + /** The empty tree */ + case object EmptyTree extends Tree { + tpe = NoType; + override def isType = true; + override def isTerm = true; + } + + /** Class definition */ + case class ClassDef(mods: int, name: Name, tparams: List[AbsTypeDef], + vparams: List[List[ValDef]], tp: Tree, impl: Template) + extends DefTree; + + /** Package clause */ + case class PackageDef(pkg: Tree, stats: List[Tree]) + extends DefTree; + + /** Singleton object definition */ + case class ModuleDef(mods: int, name: Name, tp: Tree, impl: Template) + extends DefTree; + + /** Value definition */ + case class ValDef(mods: int, name: Name, tp: Tree, rhs: Tree) + extends DefTree; + + /** Method definition */ + case class DefDef(mods: int, name: Name, tparams: List[AbsTypeDef], + vparams: List[List[ValDef]], tp: Tree, rhs: Tree) + extends DefTree; + + /** Abstract type or type parameter */ + case class AbsTypeDef(mods: int, name: Name, lo: Tree, hi: Tree, vu: Tree) + extends DefTree; + + /** Type alias */ + case class AliasTypeDef(mods: int, name: Name, tparams: List[AbsTypeDef], + rhs: Tree) + extends DefTree; + + /** Labelled expression - the symbols in the array (must be Idents!) + * are those the label takes as argument */ + case class LabelDef(name: Name, params: List[Ident], rhs: Tree) + extends DefTree with TermTree; + + /** Import clause */ + case class Import(expr: Tree, selectors: List[Name]) + extends SymTree; + + /** Pattern definition, eliminated by Analyzer */ + case class PatDef(mods: int, pat: Tree, rhs: Tree) + extends Tree; + + /** Attribuetd definition */ + case class Attributed(attribute: Tree, definition: Tree) + extends Tree; + + /** Documented definition, eliminated by analyzer */ + case class DocDef(comment: String, definition: Tree) + extends Tree; + + /** Instantiation template */ + case class Template(parents: List[Tree], body: List[Tree]) + extends SymTree; + + /** Block of expressions (semicolon separated expressions) */ + case class Block(stats: List[Tree], expr: Tree) + extends TermTree; + + /** Visitor (a sequence of cases), eliminated by TransMatch */ + case class Visitor(cases: List[CaseDef]) + extends TermTree; + + /** Case clause in a pattern match, eliminated by TransMatch */ + case class CaseDef(pat: Tree, guard: Tree, body: Tree) + extends Tree; + + /** Sequence of expression/patterns (comma separated expressions), + * eliminated by TransMatch */ + case class Sequence(trees: List[Tree]) + extends TermTree; + + /** Alternatives of patterns, eliminated by TransMatch */ + case class Alternative(trees: List[Tree]) + extends TermTree; + + /** Bind of a variable to a rhs pattern, eliminated by TransMatch */ + case class Bind(name: Name, rhs: Tree) + extends TermTree; + + /** Anonymous function, eliminated by analyzer */ + case class Function(vparams: List[ValDef], body: Tree) + extends TermTree; + + /** Assignment */ + case class Assign(lhs: Tree, rhs: Tree) + extends TermTree; + + /** Conditional expression */ + case class If(cond: Tree, thenp: Tree, elsep: Tree) + extends TermTree; + + /** For comprehension */ + case class For(enumerators: List[Tree], body: Tree, isForYield: boolean) + extends TermTree; + + /** Switch, introduced by refcheck */ + case class Switch(test: Tree, tags: List[int], bodies: List[Tree], + default: Tree) + extends TermTree; + + /** Return expression */ + case class Return(expr: Tree) + extends TermTree; + + case class Try(block: Tree, catcher: Tree, finalizer: Tree) + extends TermTree; + + /** Throw expression */ + case class Throw(expr: Tree) + extends TermTree; + + /** Object instantiation + * @param init either a constructor or a template + */ + case class New(init: Tree) + extends TermTree; + + /** Type annotation, eliminated by explicit outer */ + case class Typed(expr: Tree, tp: Tree) + extends TermTree; + + /** Type application */ + case class TypeApply(fun: Tree, args: List[Tree]) + extends TermTree; + + /** Value application */ + case class Apply(fun: Tree, args: List[Tree]) + extends TermTree; + + /** Super reference */ + case class Super(qual: Name, mixin: Name) + extends TermTree with SymTree; + + /** Self reference */ + case class This(qual: Name) + extends TermTree with SymTree; + + /** Designator */ + case class Select(qualifier: Tree, selector: Name) + extends SymTree { + override def isTerm = selector.isTermName; + override def isType = selector.isTypeName; + } + + /** Identifier */ + case class Ident(name: Name) + extends SymTree { + override def isTerm = name.isTermName; + override def isType = name.isTypeName; + } + + /** Literal */ + case class Literal(value: Any) + extends TermTree; + + /** General type term, introduced by RefCheck. */ + case class GeneralTypeTree() + extends TypeTree; + + /** Singleton type, eliminated by RefCheck */ + case class SingletonTypeTree(ref: Tree) + extends TypeTree; + + /** Type selection, eliminated by RefCheck */ + case class SelectFromTypeTree(qualifier: Tree, selector: Name) + extends TypeTree with SymTree; + + /** Function type, eliminated by RefCheck */ + case class FunctionTypeTree(argtpes: List[Tree], restpe: Tree) + extends TypeTree; + + /** Intersection type, eliminated by RefCheck */ + case class IntersectionTypeTree(parents: List[Tree]) + extends TypeTree; + + /** Refinement type, eliminated by RefCheck */ + case class RefinementTypeTree(base: Tree, members: List[Tree]) + extends TypeTree; + + /** Applied type, eliminated by RefCheck */ + case class AppliedTypeTree(tp: Tree, args: List[Tree]) + extends TypeTree; + +/* A standard pattern match + case EmptyTree => + case ClassDef(mods, name, tparams, vparams, tp, impl) => + case PackageDef(pkg, stats) => + case ModuleDef(mods, name, tp, impl) => + case ValDef(mods, name, tp, rhs) => + case DefDef(mods, name, tparams, vparams, tp, rhs) => + case AbsTypeDef(mods, name, lo, hi, vu) => + case AliasTypeDef(mods, name, tparams, rhs) => + case LabelDef(name, params, rhs) => + case Import(expr, selectors) => + case PatDef(mods, pat, rhs) => + case Attributed(attribute, definition) => + case DocDef(comment, definition) => + case Template(parents, body) => + case Block(stats, expr) => + case Visitor(cases) => + case CaseDef(pat, guard, body) => + case Sequence(trees) => + case Alternative(trees) => + case Bind(name, rhs) => + case Function(vparams, body) => + case Assign(lhs, rhs) => + case For(enumerators, body, isForYield) => + case If(cond, thenp, elsep) => + case Switch(test, tags, bodies, default) => + case Return(expr) => + case Try(block, catcher, finalizer) => + case Throw(expr) => + case New(init) => + case Typed(expr, tp) => + case TypeApply(fun, args) => + case Apply(fun, args) => + case Super(qual, mixin) => + case This(qual) => + case Select(qualifier, selector) => + case Ident(name) => + case Literal(value) => + case GeneralTypeTree() => + case SingletonTypeTree(ref) => + case SelectFromTypeTree(qualifier, selector) => + case FunctionTypeTree(argtpes, restpe) => + case IntersectionTypeTree(parents) => + case RefinementTypeTree(base, members) => + case AppliedTypeTree(tp, args) => +*/ + + trait TreeCopier { + def ClassDef(tree: Tree, mods: int, name: Name, tparams: List[AbsTypeDef], vparams: List[List[ValDef]], tp: Tree, impl: Template): ClassDef; + def PackageDef(tree: Tree, pkg: Tree, stats: List[Tree]): PackageDef; + def ModuleDef(tree: Tree, mods: int, name: Name, tp: Tree, impl: Template): ModuleDef; + def ValDef(tree: Tree, mods: int, name: Name, tp: Tree, rhs: Tree): ValDef; + def DefDef(tree: Tree, mods: int, name: Name, tparams: List[AbsTypeDef], vparams: List[List[ValDef]], tp: Tree, rhs: Tree): DefDef; + def AbsTypeDef(tree: Tree, mods: int, name: Name, lo: Tree, hi: Tree, vu: Tree): AbsTypeDef; + def AliasTypeDef(tree: Tree, mods: int, name: Name, tparams: List[AbsTypeDef], rhs: Tree): AliasTypeDef; + def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree): LabelDef; + def Import(tree: Tree, expr: Tree, selectors: List[Name]): Import; + def PatDef(tree: Tree, mods: int, pat: Tree, rhs: Tree): PatDef; + def Attributed(tree: Tree, attribute: Tree, definition: Tree): Attributed; + def DocDef(tree: Tree, comment: String, definition: Tree): DocDef; + def Template(tree: Tree, parents: List[Tree], body: List[Tree]): Template; + def Block(tree: Tree, stats: List[Tree], expr: Tree): Block; + def Visitor(tree: Tree, cases: List[CaseDef]): Visitor; + def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree): CaseDef; + def Sequence(tree: Tree, trees: List[Tree]): Sequence; + def Alternative(tree: Tree, trees: List[Tree]): Alternative; + def Bind(tree: Tree, name: Name, rhs: Tree): Bind; + def Function(tree: Tree, vparams: List[ValDef], body: Tree): Function; + def Assign(tree: Tree, lhs: Tree, rhs: Tree): Assign; + def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree): If; + def For(tree: Tree, enumerators: List[Tree], body: Tree, isForYield: boolean): For; + def Switch(tree: Tree, test: Tree, tags: List[int], bodies: List[Tree], default: Tree): Switch; + def Return(tree: Tree, expr: Tree): Return; + def Try(tree: Tree, block: Tree, catcher: Tree, finalizer: Tree): Try; + def Throw(tree: Tree, expr: Tree): Throw; + def New(tree: Tree, init: Tree): New; + def Typed(tree: Tree, expr: Tree, tp: Tree): Typed; + def TypeApply(tree: Tree, fun: Tree, args: List[Tree]): TypeApply; + def Apply(tree: Tree, fun: Tree, args: List[Tree]): Apply; + def Super(tree: Tree, qual: Name, mixin: Name): Super; + def This(tree: Tree, qual: Name): This; + def Select(tree: Tree, qualifier: Tree, selector: Name): Select; + def Ident(tree: Tree, name: Name): Ident; + def Literal(tree: Tree, value: Any): Literal; + def GeneralTypeTree(tree: Tree): GeneralTypeTree; + def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree; + def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name): SelectFromTypeTree; + def FunctionTypeTree(tree: Tree, argtpes: List[Tree], restpe: Tree): FunctionTypeTree; + def IntersectionTypeTree(tree: Tree, parents: List[Tree]): IntersectionTypeTree; + def RefinementTypeTree(tree: Tree, base: Tree, members: List[Tree]): RefinementTypeTree; + def AppliedTypeTree(tree: Tree, tp: Tree, args: List[Tree]): AppliedTypeTree; + } + + class StrictTreeCopier extends TreeCopier { + def ClassDef(tree: Tree, mods: int, name: Name, tparams: List[AbsTypeDef], vparams: List[List[ValDef]], tp: Tree, impl: Template) = + { val t = new ClassDef(mods, name, tparams, vparams, tp, impl); t.setPos(tree.pos); t } + def PackageDef(tree: Tree, pkg: Tree, stats: List[Tree]) = + { val t = new PackageDef(pkg, stats); t.setPos(tree.pos); t } + def ModuleDef(tree: Tree, mods: int, name: Name, tp: Tree, impl: Template) = + { val t = new ModuleDef(mods, name, tp, impl); t.setPos(tree.pos); t } + def ValDef(tree: Tree, mods: int, name: Name, tp: Tree, rhs: Tree) = + { val t = new ValDef(mods, name, tp, rhs); t.setPos(tree.pos); t } + def DefDef(tree: Tree, mods: int, name: Name, tparams: List[AbsTypeDef], vparams: List[List[ValDef]], tp: Tree, rhs: Tree) = + { val t = new DefDef(mods, name, tparams, vparams, tp, rhs); t.setPos(tree.pos); t } + def AbsTypeDef(tree: Tree, mods: int, name: Name, lo: Tree, hi: Tree, vu: Tree) = + { val t = new AbsTypeDef(mods, name, lo, hi, vu); t.setPos(tree.pos); t } + def AliasTypeDef(tree: Tree, mods: int, name: Name, tparams: List[AbsTypeDef], rhs: Tree) = + { val t = new AliasTypeDef(mods, name, tparams, rhs); t.setPos(tree.pos); t } + def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) = + { val t = new LabelDef(name, params, rhs); t.setPos(tree.pos); t } + def Import(tree: Tree, expr: Tree, selectors: List[Name]) = + { val t = new Import(expr, selectors); t.setPos(tree.pos); t } + def PatDef(tree: Tree, mods: int, pat: Tree, rhs: Tree) = + { val t = new PatDef(mods, pat, rhs); t.setPos(tree.pos); t } + def Attributed(tree: Tree, attribute: Tree, definition: Tree) = + { val t = new Attributed(attribute, definition); t.setPos(tree.pos); t } + def DocDef(tree: Tree, comment: String, definition: Tree) = + { val t = new DocDef(comment, definition); t.setPos(tree.pos); t } + def Template(tree: Tree, parents: List[Tree], body: List[Tree]) = + { val t = new Template(parents, body); t.setPos(tree.pos); t } + def Block(tree: Tree, stats: List[Tree], expr: Tree) = + { val t = new Block(stats, expr); t.setPos(tree.pos); t } + def Visitor(tree: Tree, cases: List[CaseDef]) = + { val t = new Visitor(cases); t.setPos(tree.pos); t } + def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) = + { val t = new CaseDef(pat, guard, body); t.setPos(tree.pos); t } + def Sequence(tree: Tree, trees: List[Tree]) = + { val t = new Sequence(trees); t.setPos(tree.pos); t } + def Alternative(tree: Tree, trees: List[Tree]) = + { val t = new Alternative(trees); t.setPos(tree.pos); t } + def Bind(tree: Tree, name: Name, rhs: Tree) = + { val t = new Bind(name, rhs); t.setPos(tree.pos); t } + def Function(tree: Tree, vparams: List[ValDef], body: Tree) = + { val t = new Function(vparams, body); t.setPos(tree.pos); t } + def Assign(tree: Tree, lhs: Tree, rhs: Tree) = + { val t = new Assign(lhs, rhs); t.setPos(tree.pos); t } + def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = + { val t = new If(cond, thenp, elsep); t.setPos(tree.pos); t } + def For(tree: Tree, enumerators: List[Tree], body: Tree, isForYield: boolean) = + { val t = new For(enumerators, body, isForYield); t.setPos(tree.pos); t } + def Switch(tree: Tree, test: Tree, tags: List[int], bodies: List[Tree], default: Tree) = + { val t = new Switch(test, tags, bodies, default); t.setPos(tree.pos); t } + def Return(tree: Tree, expr: Tree) = + { val t = new Return(expr); t.setPos(tree.pos); t } + def Try(tree: Tree, block: Tree, catcher: Tree, finalizer: Tree) = + { val t = new Try(block, catcher, finalizer); t.setPos(tree.pos); t } + def Throw(tree: Tree, expr: Tree) = + { val t = new Throw(expr); t.setPos(tree.pos); t } + def New(tree: Tree, init: Tree) = + { val t = new New(init); t.setPos(tree.pos); t } + def Typed(tree: Tree, expr: Tree, tp: Tree) = + { val t = new Typed(expr, tp); t.setPos(tree.pos); t } + def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) = + { val t = new TypeApply(fun, args); t.setPos(tree.pos); t } + def Apply(tree: Tree, fun: Tree, args: List[Tree]) = + { val t = new Apply(fun, args); t.setPos(tree.pos); t } + def Super(tree: Tree, qual: Name, mixin: Name) = + { val t = new Super(qual, mixin); t.setPos(tree.pos); t } + def This(tree: Tree, qual: Name) = + { val t = new This(qual); t.setPos(tree.pos); t } + def Select(tree: Tree, qualifier: Tree, selector: Name) = + { val t = new Select(qualifier, selector); t.setPos(tree.pos); t } + def Ident(tree: Tree, name: Name) = + { val t = new Ident(name); t.setPos(tree.pos); t } + def Literal(tree: Tree, value: Any) = + { val t = new Literal(value); t.setPos(tree.pos); t } + def GeneralTypeTree(tree: Tree) = + { val t = new GeneralTypeTree(); t.setPos(tree.pos); t } + def SingletonTypeTree(tree: Tree, ref: Tree) = + { val t = new SingletonTypeTree(ref); t.setPos(tree.pos); t } + def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) = + { val t = new SelectFromTypeTree(qualifier, selector); t.setPos(tree.pos); t } + def FunctionTypeTree(tree: Tree, argtpes: List[Tree], restpe: Tree) = + { val t = new FunctionTypeTree(argtpes, restpe); t.setPos(tree.pos); t } + def IntersectionTypeTree(tree: Tree, parents: List[Tree]) = + { val t = new IntersectionTypeTree(parents); t.setPos(tree.pos); t } + def RefinementTypeTree(tree: Tree, base: Tree, members: List[Tree]) = + { val t = new RefinementTypeTree(base, members); t.setPos(tree.pos); t } + def AppliedTypeTree(tree: Tree, tp: Tree, args: List[Tree]) = + { val t = new AppliedTypeTree(tp, args); t.setPos(tree.pos); t } + } + + class LazyTreeCopier(copy: TreeCopier) extends TreeCopier { + def this() = this(new StrictTreeCopier); + def ClassDef(tree: Tree, mods: int, name: Name, tparams: List[AbsTypeDef], vparams: List[List[ValDef]], tp: Tree, impl: Template) = tree match { + case t @ ClassDef(mods0, name0, tparams0, vparams0, tp0, impl0) + if (mods0 == mods && name0 == name && tparams0 == tparams && vparams0 == vparams && tp0 == tp && impl0 == impl) => t + case _ => copy.ClassDef(tree, mods, name, tparams, vparams, tp, impl) + } + def PackageDef(tree: Tree, pkg: Tree, stats: List[Tree]) = tree match { + case t @ PackageDef(pkg0, stats0) + if (pkg0 == pkg && stats0 == stats) => t + case _ => copy.PackageDef(tree, pkg, stats) + } + def ModuleDef(tree: Tree, mods: int, name: Name, tp: Tree, impl: Template) = tree match { + case t @ ModuleDef(mods0, name0, tp0, impl0) + if (mods0 == mods && name0 == name && tp0 == tp && impl0 == impl) => t + case _ => copy.ModuleDef(tree, mods, name, tp, impl) + } + def ValDef(tree: Tree, mods: int, name: Name, tp: Tree, rhs: Tree) = tree match { + case t @ ValDef(mods0, name0, tp0, rhs0) + if (mods0 == mods && name0 == name && tp0 == tp && rhs0 == rhs) => t + case _ => copy.ValDef(tree, mods, name, tp, rhs) + } + def DefDef(tree: Tree, mods: int, name: Name, tparams: List[AbsTypeDef], vparams: List[List[ValDef]], tp: Tree, rhs: Tree) = tree match { + case t @ DefDef(mods0, name0, tparams0, vparams0, tp0, rhs0) + if (mods0 == mods && name0 == name && tparams0 == tparams && vparams0 == vparams && tp0 == tp && rhs == rhs0) => t + case _ => copy.DefDef(tree, mods, name, tparams, vparams, tp, rhs) + } + def AbsTypeDef(tree: Tree, mods: int, name: Name, lo: Tree, hi: Tree, vu: Tree) = tree match { + case t @ AbsTypeDef(mods0, name0, lo0, hi0, vu0) + if (mods0 == mods && name0 == name && lo0 == lo && hi0 == hi && vu0 == vu) => t + case _ => copy.AbsTypeDef(tree, mods, name, lo, hi, vu) + } + def AliasTypeDef(tree: Tree, mods: int, name: Name, tparams: List[AbsTypeDef], rhs: Tree) = tree match { + case t @ AliasTypeDef(mods0, name0, tparams0, rhs0) + if (mods0 == mods && name0 == name && tparams0 == tparams && rhs0 == rhs) => t + case _ => copy.AliasTypeDef(tree, mods, name, tparams, rhs) + } + def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) = tree match { + case t @ LabelDef(name0, params0, rhs0) + if (name0 == name && params0 == params && rhs0 == rhs) => t + case _ => copy.LabelDef(tree, name, params, rhs) + } + def Import(tree: Tree, expr: Tree, selectors: List[Name]) = tree match { + case t @ Import(expr0, selectors0) + if (expr0 == expr && selectors0 == selectors) => t + case _ => copy.Import(tree, expr, selectors) + } + def PatDef(tree: Tree, mods: int, pat: Tree, rhs: Tree) = tree match { + case t @ PatDef(mods0, pat0, rhs0) + if (mods0 == mods && pat0 == pat && rhs0 == rhs) => t + case _ => copy.PatDef(tree, mods, pat, rhs) + } + def Attributed(tree: Tree, attribute: Tree, definition: Tree) = tree match { + case t @ Attributed(attribute0, definition0) + if (attribute0 == attribute && definition0 == definition) => t + case _ => copy.Attributed(tree, attribute, definition) + } + def DocDef(tree: Tree, comment: String, definition: Tree) = tree match { + case t @ DocDef(comment0, definition0) + if (comment0 == comment && definition0 == definition) => t + case _ => copy.DocDef(tree, comment, definition) + } + def Template(tree: Tree, parents: List[Tree], body: List[Tree]) = tree match { + case t @ Template(parents0, body0) + if (parents0 == parents && body0 == body) => t + case _ => copy.Template(tree, parents, body) + } + def Block(tree: Tree, stats: List[Tree], expr: Tree) = tree match { + case t @ Block(stats0, expr0) + if (stats0 == stats && expr0 == expr) => t + case _ => copy.Block(tree, stats, expr) + } + def Visitor(tree: Tree, cases: List[CaseDef]) = tree match { + case t @ Visitor(cases0) + if (cases == cases0) => t + case _ => copy.Visitor(tree, cases) + } + def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) = tree match { + case t @ CaseDef(pat0, guard0, body0) + if (pat0 == pat && guard0 == guard && body0 == body) => t + case _ => copy.CaseDef(tree, pat, guard, body) + } + def Sequence(tree: Tree, trees: List[Tree]) = tree match { + case t @ Sequence(trees0) + if (trees0 == trees) => t + case _ => copy.Sequence(tree, trees) + } + def Alternative(tree: Tree, trees: List[Tree]) = tree match { + case t @ Alternative(trees0) + if (trees0 == trees) => t + case _ => copy.Alternative(tree, trees) + } + def Bind(tree: Tree, name: Name, rhs: Tree) = tree match { + case t @ Bind(name0, rhs0) + if (name0 == name && rhs0 == rhs) => t + case _ => copy.Bind(tree, name, rhs) + } + def Function(tree: Tree, vparams: List[ValDef], body: Tree) = tree match { + case t @ Function(vparams0, body0) + if (vparams0 == vparams && body0 == body) => t + case _ => copy.Function(tree, vparams, body) + } + def Assign(tree: Tree, lhs: Tree, rhs: Tree) = tree match { + case t @ Assign(lhs0, rhs0) + if (lhs0 == lhs && rhs0 == rhs) => t + case _ => copy.Assign(tree, lhs, rhs) + } + def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = tree match { + case t @ If(cond0, thenp0, elsep0) + if (cond0 == cond && thenp0 == thenp && elsep0 == elsep) => t + case _ => copy.If(tree, cond, thenp, elsep) + } + def For(tree: Tree, enumerators: List[Tree], body: Tree, isForYield: boolean) = tree match { + case t @ For(enumerators0, body0, isForYield0) + if (enumerators0 == enumerators && body0 == body && isForYield0 == isForYield) => t + case _ => copy.For(tree, enumerators, body, isForYield) + } + def Switch(tree: Tree, test: Tree, tags: List[int], bodies: List[Tree], default: Tree) = tree match { + case t @ Switch(test0, tags0, bodies0, default0) + if (test0 == test && tags0 == tags && bodies0 == bodies && default0 == default) => t + case _ => copy.Switch(tree, test, tags, bodies, default) + } + def Return(tree: Tree, expr: Tree) = tree match { + case t @ Return(expr0) + if (expr0 == expr) => t + case _ => copy.Return(tree, expr) + } + def Try(tree: Tree, block: Tree, catcher: Tree, finalizer: Tree) = tree match { + case t @ Try(block0, catcher0, finalizer0) + if (block0 == block && catcher0 == catcher && finalizer0 == finalizer) => t + case _ => copy.Try(tree, block, catcher, finalizer) + } + def Throw(tree: Tree, expr: Tree) = tree match { + case t @ Throw(expr0) + if (expr0 == expr) => t + case _ => copy.Throw(tree, expr) + } + def New(tree: Tree, init: Tree) = tree match { + case t @ New(init0) + if (init0 == init) => t + case _ => copy.New(tree, init) + } + def Typed(tree: Tree, expr: Tree, tp: Tree) = tree match { + case t @ Typed(expr0, tp0) + if (expr0 == expr && tp0 == tp) => t + case _ => copy.Typed(tree, expr, tp) + } + def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { + case t @ TypeApply(fun0, args0) + if (fun0 == fun && args0 == args) => t + case _ => copy.TypeApply(tree, fun, args) + } + def Apply(tree: Tree, fun: Tree, args: List[Tree]) = tree match { + case t @ Apply(fun0, args0) + if (fun0 == fun && args0 == args) => t + case _ => copy.Apply(tree, fun, args) + } + def Super(tree: Tree, qual: Name, mixin: Name) = tree match { + case t @ Super(qual0, mixin0) + if (qual0 == qual && mixin0 == mixin) => t + case _ => copy.Super(tree, qual, mixin) + } + def This(tree: Tree, qual: Name) = tree match { + case t @ This(qual0) + if (qual0 == qual) => t + case _ => copy.This(tree, qual) + } + def Select(tree: Tree, qualifier: Tree, selector: Name) = tree match { + case t @ Select(qualifier0, selector0) + if (qualifier0 == qualifier && selector0 == selector) => t + case _ => copy.Select(tree, qualifier, selector) + } + def Ident(tree: Tree, name: Name) = tree match { + case t @ Ident(name0) + if (name0 == name) => t + case _ => copy.Ident(tree, name) + } + def Literal(tree: Tree, value: Any) = tree match { + case t @ Literal(value0) + if (value0 == value) => t + case _ => copy.Literal(tree, value) + } + def GeneralTypeTree(tree: Tree) = tree match { + case t @ GeneralTypeTree() => t + case _ => copy.GeneralTypeTree(tree) + } + def SingletonTypeTree(tree: Tree, ref: Tree) = tree match { + case t @ SingletonTypeTree(ref0) + if (ref0 == ref) => t + case _ => copy.SingletonTypeTree(tree, ref) + } + def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) = tree match { + case t @ SelectFromTypeTree(qualifier0, selector0) + if (qualifier0 == qualifier && selector0 == selector) => t + case _ => copy.SelectFromTypeTree(tree, qualifier, selector) + } + def FunctionTypeTree(tree: Tree, argtpes: List[Tree], restpe: Tree) = tree match { + case t @ FunctionTypeTree(argtpes0, restpe0) + if (argtpes0 == argtpes && restpe0 == restpe) => t + case _ => copy.FunctionTypeTree(tree, argtpes, restpe) + } + def IntersectionTypeTree(tree: Tree, parents: List[Tree]) = tree match { + case t @ IntersectionTypeTree(parents0) + if (parents0 == parents) => t + case _ => copy.IntersectionTypeTree(tree, parents) + } + def RefinementTypeTree(tree: Tree, base: Tree, members: List[Tree]) = tree match { + case t @ RefinementTypeTree(base0, members0) + if (base0 == base && members0 == members) => t + case _ => copy.RefinementTypeTree(tree, base, members) + } + def AppliedTypeTree(tree: Tree, tp: Tree, args: List[Tree]) = tree match { + case t @ AppliedTypeTree(tp0, args0) + if (tp0 == tp && args0 == args) => t + case _ => copy.AppliedTypeTree(tree, tp, args) + } + } + + class Transformer(copy: TreeCopier) { + def this() = this(new LazyTreeCopier); + def transform(tree: Tree): Tree = tree match { + case EmptyTree => + tree + case ClassDef(mods, name, tparams, vparams, tp, impl) => + copy.ClassDef(tree, mods, name, transformAbsTypeDefs(tparams), transformValDefss(vparams), transform(tp), transformTemplate(impl)) + case PackageDef(pkg, stats) => + copy.PackageDef(tree, transform(pkg), transform(stats)) + case ModuleDef(mods, name, tp, impl) => + copy.ModuleDef(tree, mods, name, transform(tp), transformTemplate(impl)) + case ValDef(mods, name, tp, rhs) => + copy.ValDef(tree, mods, name, transform(tp), transform(rhs)) + case DefDef(mods, name, tparams, vparams, tp, rhs) => + copy.DefDef(tree, mods, name, transformAbsTypeDefs(tparams), transformValDefss(vparams), transform(tp), transform(rhs)) + case AbsTypeDef(mods, name, lo, hi, vu) => + copy.AbsTypeDef(tree, mods, name, transform(lo), transform(hi), transform(vu)) + case AliasTypeDef(mods, name, tparams, rhs) => + copy.AliasTypeDef(tree, mods, name, transformAbsTypeDefs(tparams), transform(rhs)) + case LabelDef(name, params, rhs) => + copy.LabelDef(tree, name, transformIdents(params), transform(rhs)) + case Import(expr, selectors) => + copy.Import(tree, transform(expr), selectors) + case PatDef(mods, pat, rhs) => + copy.PatDef(tree, mods, transform(pat), transform(rhs)) + case Attributed(attribute, definition) => + copy.Attributed(tree, transform(attribute), transform(definition)) + case DocDef(comment, definition) => + copy.DocDef(tree, comment, transform(definition)) + case Template(parents, body) => + copy.Template(tree, transform(parents), transform(body)) + case Block(stats, expr) => + copy.Block(tree, transform(stats), transform(expr)) + case Visitor(cases) => + copy.Visitor(tree, transformCaseDefs(cases)) + case CaseDef(pat, guard, body) => + copy.CaseDef(tree, transform(pat), transform(guard), transform(body)) + case Sequence(trees) => + copy.Sequence(tree, transform(trees)) + case Alternative(trees) => + copy.Alternative(tree, transform(trees)) + case Bind(name, rhs) => + copy.Bind(tree, name, transform(rhs)) + case Function(vparams, body) => + copy.Function(tree, transformValDefs(vparams), transform(body)) + case Assign(lhs, rhs) => + copy.Assign(tree, transform(lhs), transform(rhs)) + case For(enumerators, body: Tree, isForYield) => + copy.For(tree, transform(enumerators), transform(body), isForYield) + case If(cond, thenp, elsep) => + copy.If(tree, transform(cond), transform(thenp), transform(elsep)) + case Switch(test, tags, bodies, default) => + copy.Switch(tree, transform(test), tags, transform(bodies), transform(default)) + case Return(expr) => + copy.Return(tree, transform(expr)) + case Try(block, catcher, finalizer) => + copy.Try(tree, transform(block), transform(catcher), transform(finalizer)) + case Throw(expr) => + copy.Throw(tree, transform(expr)) + case New(init) => + copy.New(tree, transform(init)) + case Typed(expr, tp) => + copy.Typed(tree, transform(expr), transform(tp)) + case TypeApply(fun, args) => + copy.TypeApply(tree, transform(fun), transform(args)) + case Apply(fun, args) => + copy.Apply(tree, transform(fun), transform(args)) + case Super(qual, mixin) => + copy.Super(tree, qual, mixin) + case This(qual) => + copy.This(tree, qual) + case Select(qualifier, selector) => + copy.Select(tree, transform(qualifier), selector) + case Ident(name) => + copy.Ident(tree, name) + case Literal(value) => + copy.Literal(tree, value) + case GeneralTypeTree() => + copy.GeneralTypeTree(tree) + case SingletonTypeTree(ref) => + copy.SingletonTypeTree(tree, transform(ref)) + case SelectFromTypeTree(qualifier, selector) => + copy.SelectFromTypeTree(tree, transform(qualifier), selector) + case FunctionTypeTree(argtpes, restpe) => + copy.FunctionTypeTree(tree, transform(argtpes), transform(restpe)) + case IntersectionTypeTree(parents) => + copy.IntersectionTypeTree(tree, transform(parents)) + case RefinementTypeTree(base, members) => + copy.RefinementTypeTree(tree, transform(base), transform(members)) + case AppliedTypeTree(tp, args) => + copy.AppliedTypeTree(tree, transform(tp), transform(args)) + } + + def transform(trees: List[Tree]): List[Tree] = + trees map transform; + def transformTemplate(tree: Template): Template = + transform(tree: Tree).asInstanceOf[Template]; + def transformAbsTypeDefs(trees: List[AbsTypeDef]): List[AbsTypeDef] = + trees map (tree => transform(tree).asInstanceOf[AbsTypeDef]); + def transformValDefs(trees: List[ValDef]): List[ValDef] = + trees map (tree => transform(tree).asInstanceOf[ValDef]); + def transformValDefss(treess: List[List[ValDef]]): List[List[ValDef]] = + treess map transformValDefs; + def transformCaseDefs(trees: List[CaseDef]): List[CaseDef] = + trees map (tree => transform(tree).asInstanceOf[CaseDef]); + def transformIdents(trees: List[Ident]): List[Ident] = + trees map (tree => transform(tree).asInstanceOf[Ident]); + } + + class Traverser { + def traverse(tree: Tree): unit = tree match { + case ClassDef(mods, name, tparams, vparams, tp, impl) => + traverse(tparams); traverseTreess(vparams); traverse(tp); traverse(impl) + case PackageDef(pkg, stats) => + traverse(pkg); traverse(stats) + case ModuleDef(mods, name, tp, impl) => + traverse(tp); traverse(impl) + case ValDef(mods, name, tp, rhs) => + traverse(tp); traverse(rhs) + case DefDef(mods, name, tparams, vparams, tp, rhs) => + traverse(tparams); traverseTreess(vparams); traverse(tp); traverse(rhs) + case AbsTypeDef(mods, name, lo, hi, vu) => + traverse(lo); traverse(hi); traverse(vu) + case AliasTypeDef(mods, name, tparams, rhs) => + traverse(tparams); traverse(rhs) + case LabelDef(name, params, rhs) => + traverse(params); traverse(rhs) + case Import(expr, selectors) => + traverse(expr) + case PatDef(mods, pat, rhs) => + traverse(pat); traverse(rhs) + case Attributed(attribute, definition) => + traverse(attribute); traverse(definition) + case DocDef(comment, definition) => + traverse(definition) + case Template(parents, body) => + traverse(parents); traverse(body) + case Block(stats, expr) => + traverse(stats); traverse(expr) + case Visitor(cases) => + traverse(cases) + case CaseDef(pat, guard, body) => + traverse(pat); traverse(guard); traverse(body) + case Sequence(trees) => + traverse(trees) + case Alternative(trees) => + traverse(trees) + case Bind(name, rhs) => + traverse(rhs) + case Function(vparams, body) => + traverse(vparams); traverse(body) + case Assign(lhs, rhs) => + traverse(lhs); traverse(rhs) + case For(enumerators, body: Tree, isForYield) => + traverse(enumerators); traverse(body) + case If(cond, thenp, elsep) => + traverse(cond); traverse(thenp); traverse(elsep) + case Switch(test, tags, bodies, default) => + traverse(test); traverse(bodies); traverse(default) + case Return(expr) => + traverse(expr) + case Try(block, catcher, finalizer) => + traverse(block); traverse(catcher); traverse(finalizer) + case Throw(expr) => + traverse(expr) + case New(init) => + traverse(init) + case Typed(expr, tp) => + traverse(expr); traverse(tp) + case TypeApply(fun, args) => + traverse(fun); traverse(args) + case Apply(fun, args) => + traverse(fun); traverse(args) + case Select(qualifier, selector) => + traverse(qualifier) + case SingletonTypeTree(ref) => + traverse(ref) + case SelectFromTypeTree(qualifier, selector) => + traverse(qualifier) + case FunctionTypeTree(argtpes, restpe) => + traverse(argtpes); traverse(restpe) + case IntersectionTypeTree(parents) => + traverse(parents) + case RefinementTypeTree(base, members) => + traverse(base); traverse(members) + case AppliedTypeTree(tp, args) => + traverse(tp); traverse(args) + case EmptyTree | Super(_, _) | This(_) | Ident(_) | Literal(_) | GeneralTypeTree() => + {} + } + + def traverse(trees: List[Tree]): unit = + trees foreach traverse; + def traverseTreess(treess: List[List[Tree]]): unit = + treess foreach traverse; + } + + final class TreeList { + private var trees = List[Tree](); + def append(t: Tree): TreeList = { trees = t :: trees; this } + def append(ts: List[Tree]): TreeList = { trees = ts reverse_::: trees; this } + def toList: List[Tree] = trees.reverse; + } + + object posAssigner extends Traverser { + private var pos: int = _; + override def traverse(t: Tree): unit = + if (t != EmptyTree && t.pos == Position.NOPOS) { + t.pos = pos; + super.traverse(t); + } + def atPos[T <: Tree](pos: int)(tree: T): T = { + this.pos = pos; + traverse(tree); + tree + } + } +} + diff --git a/sources/scala/tools/nsc/ast/parser/Lexical.scala b/sources/scala/tools/nsc/ast/parser/Lexical.scala new file mode 100644 index 0000000000..b3d12948c5 --- /dev/null +++ b/sources/scala/tools/nsc/ast/parser/Lexical.scala @@ -0,0 +1,857 @@ +package scala.tools.nsc.ast.parser; + +import Tokens._; +import scala.tools.util.{Position, SourceFile} +import SourceFile.{LF, FF, CR, SU} +import scala.tools.nsc.util.CharArrayReader; + +abstract class Lexical: ParserPhase { + + import global._; + + /** A class for representing a token's data. */ + class TokenData { + + /** the next token */ + var token: int = EMPTY; + + /** the token's position */ + var pos: int = 0; + + /** the name of an identifier or token */ + var name: Name = null; + + /** the base of a number */ + var base: int = 0; + + def copyFrom(td: TokenData) = { + this.token = td.token; + this.pos = td.pos; + this.name = td.name; + this.base = td.base; + } + } + + /** A scanner for the programming language Scala. + * + * @author Matthias Zenger, Martin Odersky, Burak Emir + * @version 1.1 + */ + class Scanner(unit: CompilationUnit) extends TokenData { + + import Tokens._; + import java.lang.{Integer, Long, Float, Double, Character} + + /** Character input reader + */ + val in = new CharArrayReader(unit.source.getContent(), true, syntaxError); + + /** character buffer for literals + */ + val cbuf = new StringBuffer(); + + /** append Unicode character to "lit" buffer + */ + protected def putChar(c: char) = cbuf.append(c); + + /** Clear buffer and set name */ + private def setName = { + name = newTermName(cbuf.toString()); + cbuf.setLength(0) + } + + /** buffer for the documentation comment + */ + var docBuffer: StringBuffer = null; + + /** add the given character to the documentation buffer + */ + protected def putDocChar(c: char): unit = + if (docBuffer != null) docBuffer.append(c); + + /** we need one token lookahead + */ + val next = new TokenData(); + val prev = new TokenData(); + + /** the first character position after the previous token + */ + var lastpos = 0; + + /** the last error position + */ + var errpos = -1; + +// Get next token ------------------------------------------------------------ + + /** 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 || Position.line(pos) > Position.line(prevpos)) { + 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); + } + } + //Console.println("<" + this + ">");//DEBUG + } + } + + /** read next token + */ + private def fetchToken(): unit = { + if (token == EOF) return; + lastpos = Position.encode(in.cline, in.ccol); + //var index = bp; + while (true) { + in.ch match { + case ' ' | '\t' | CR | LF | FF => + in.next; + case _ => + pos = Position.encode(in.cline, in.ccol); + in.ch match { + case '\u21D2' => + in.next; token = ARROW; + return; + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | '_' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns + 'z' => + putChar(in.ch); + in.next; + getIdentRest; // scala-mode: wrong indent for multi-line case blocks + return; + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | '=' | '&' | + '|' | '\\' => + putChar(in.ch); + in.next; + getOperatorRest; // XXX + return; + case '/' => + in.next; + if (!skipComment()) { + putChar('/'); + getOperatorRest; + return; + } + + case '0' => + putChar(in.ch); + in.next; + if (in.ch == 'x' || in.ch == 'X') { + in.next; + base = 16 + } else { + base = 8; + } + getNumber; + return; // scala-mode: return is a keyword + case '1' | '2' | '3' | '4' | + '5' | '6' | '7' | '8' | '9' => + base = 10; + getNumber; + return; + case '`' => //" scala-mode: need to understand literals + getStringLit('`'); + token = IDENTIFIER; + return; + case '\"' => //" scala-mode: need to understand literals + getStringLit('\"'); + return; + case '\'' => + in.next; + in.ch match { + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | '_' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | + 'z' => + putChar(in.ch); + in.next; + if (in.ch != '\'') { + getIdentRest; + token = SYMBOLLIT; + return; + } + case _ => + if (Character.isUnicodeIdentifierStart(in.ch)) { + putChar(in.ch); + in.next; + if (in.ch != '\'') { + getIdentRest; + token = SYMBOLLIT; + return; + } + } else { + getlitch() + } + } + if (in.ch == '\'') { + in.next; + token = CHARLIT; + setName + } else { + syntaxError("unclosed character literal"); + } + return; + case '.' => + in.next; + if ('0' <= in.ch && in.ch <= '9') { + putChar('.'); getFraction; + } else { + token = DOT + } + return; + case ';' => + in.next; token = SEMI; + return; + case ',' => + in.next; token = COMMA; + return; + case '(' => //scala-mode: need to understand character quotes + in.next; token = LPAREN; + return; + case '{' => + in.next; token = LBRACE; + return; + case ')' => + in.next; token = RPAREN; + return; + case '}' => + in.next; token = RBRACE; + return; + case '[' => + in.next; token = LBRACKET; + return; + case ']' => + in.next; token = RBRACKET; + return; + case SU => + if (!in.hasNext) token = EOF; + else syntaxError("illegal character"); + return; + case _ => + if (Character.isUnicodeIdentifierStart(in.ch)) { + putChar(in.ch); + in.next; + getIdentRest; + } else if (isSpecial(in.ch)) { + putChar(in.ch); + getOperatorRest; + } else { + syntaxError("illegal character"); + in.next; + } + return; + } + } + } + } + + private def skipComment(): boolean = + if (in.ch == '/') { + do { + in.next; + } while ((in.ch != CR) && (in.ch != LF) && (in.ch != SU)); + true + } else if (in.ch == '*') { + docBuffer = null; + var openComments = 1; + in.next; + if (in.ch == '*') docBuffer = new StringBuffer("/**"); + while (openComments > 0) { + do { + do { + if (in.ch == '/') { + in.next; putDocChar(in.ch); + if (in.ch == '*') { + in.next; putDocChar(in.ch); + openComments = openComments + 1; + } + } + in.next; putDocChar(in.ch); + } while (in.ch != '*' && in.ch != SU); + while (in.ch == '*') { + in.next; putDocChar(in.ch); + } + } while (in.ch != '/' && in.ch != SU); + if (in.ch == '/') in.next; + else syntaxError("unclosed comment"); + openComments = openComments - 1; + } + true + } else { + false + } + +// Identifiers --------------------------------------------------------------- + + def isIdentStart(c: char): boolean = + ('A' <= c && c <= 'Z') || + ('a' <= c && c <= 'a') || + (c == '_') || (c == '$') || + Character.isUnicodeIdentifierStart(c); + + def isIdentPart(c: char) = + isIdentStart(c) || + ('0' <= c && c <= '9') || + Character.isUnicodeIdentifierPart(c); + + def isSpecial(c: char) = { + val chtp = Character.getType(c); + chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL; + } + + private def getIdentRest: unit = + while (true) { + in.ch match { + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | + 'z' | + '0' | '1' | '2' | '3' | '4' | + '5' | '6' | '7' | '8' | '9' => + putChar(in.ch); + in.next; + case '_' => + putChar(in.ch); + in.next; + getIdentOrOperatorRest; + return; + case _ => + if(java.lang.Character.isUnicodeIdentifierPart(in.ch)) { + putChar(in.ch); + in.next + } else { + setName; + token = name2token(name); + return + } + } + } + + private def getOperatorRest: unit = + while (true) { + in.ch match { + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | '=' | '&' | + '|' | '\\' => + putChar(in.ch); + in.next + case '/' => + in.next; + if (skipComment()) { + setName; + token = name2token(name); + return; + } else { + putChar('/'); + } + case _ => + if (isSpecial(in.ch)) { + putChar(in.ch); + in.next; + } else { + setName; + token = name2token(name); + return; + } + } + } + + private def getIdentOrOperatorRest: unit = + if (isIdentPart(in.ch)) + getIdentRest + else in.ch match { + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | '=' | '&' | + '|' | '\\' | '/' => + getOperatorRest; + case _ => + if (isSpecial(in.ch)) getOperatorRest + else { + setName; + token = name2token(name) + } + } + + private def getStringLit(delimiter: char): unit = { + in.next; + while (in.ch != delimiter && in.ch != CR && in.ch != LF && in.ch != SU) { + getlitch(); + } + if (in.ch == delimiter) { + token = STRINGLIT; + setName; + in.next + } else { + syntaxError("unclosed string literal"); + } + } + +// Literals ----------------------------------------------------------------- + + /** read next character in character or string literal: + */ + protected def getlitch() = + if (in.ch == '\\') { + in.next; + if ('0' <= in.ch && in.ch <= '7') { + val leadch: char = in.ch; + var oct: int = in.digit2int(in.ch, 8); + in.next; + if ('0' <= in.ch && in.ch <= '7') { + oct = oct * 8 + in.digit2int(in.ch, 8); + in.next; + if (leadch <= '3' && '0' <= in.ch && in.ch <= '7') { + oct = oct * 8 + in.digit2int(in.ch, 8); + in.next; + } + } + putChar(oct.asInstanceOf[char]); + } else + in.ch match { + case 'b' => putChar('\b') + case 't' => putChar('\t') + case 'n' => putChar('\n') + case 'f' => putChar('\f') + case 'r' => putChar('\r') + case '\"' => putChar('\"') + case '\'' => putChar('\'') + case '\\' => putChar('\\') + case _ => + syntaxError(Position.encode(in.cline, in.ccol - 1), + "invalid escape character"); + putChar(in.ch); + } + in.next; + } else { + putChar(in.ch); + in.next; + } + + /** read fractional part and exponent of floating point number + * if one is present. + */ + protected def getFraction = { + while ('0' <= in.ch && in.ch <= '9') { + putChar(in.ch); + in.next; + token = DOUBLELIT; + } + if (in.ch == 'e' || in.ch == 'E') { + val lookahead = in.copy; + lookahead.next; + if (lookahead.ch == '+' || lookahead.ch == '-') { + lookahead.next; + } + if ('0' <= lookahead.ch && lookahead.ch <= '9') { + putChar(in.ch); + in.next; + if (in.ch == '+' || in.ch == '-') { + putChar(in.ch); + in.next; + } + while ('0' <= in.ch && in.ch <= '9') { + putChar(in.ch); + in.next; + } + } + token = DOUBLELIT; + } + if ((in.ch == 'd') || (in.ch == 'D')) { + putChar(in.ch); + in.next; + token = DOUBLELIT; + } else if ((in.ch == 'f') || (in.ch == 'F')) { + putChar(in.ch); + in.next; + token = FLOATLIT; + } + setName + } + + /** convert name to long value + */ + def intVal(negated: boolean): long = { + if (token == CHARLIT && !negated) { + if (name.length > 0) name(0) else 0 + } else { + var value: long = 0; + val divider = if (base == 10) 1 else 2; + val limit: long = + if (token == LONGLIT) Long.MAX_VALUE else Integer.MAX_VALUE; + var i = 0; + val len = name.length; + while (i < len) { + val d = in.digit2int(name(i), base); + if (d < 0) { + syntaxError("malformed integer number"); + return 0; + } + if (value < 0 || + limit / (base / divider) < value || + limit - (d / divider) < value * (base / divider) && + !(negated && limit == value * base - 1 + d)) { + syntaxError("integer number too large"); + return 0; + } + value = value * base + d; + i = i + 1; + } + if (negated) -value else value + } + } + + def intVal: long = intVal(false); + + /** convert name, base to double value + */ + def floatVal(negated: boolean): double = { + val limit: double = + if (token == DOUBLELIT) Double.MAX_VALUE else Float.MAX_VALUE; + try { + val value = Double.valueOf(name.toString()).doubleValue(); + if (value > limit) + syntaxError("floating point number too large"); + if (negated) -value else value + } catch { + case _: NumberFormatException => + syntaxError("malformed floating point number"); + 0.0 + } + } + + def floatVal: double = floatVal(false); + + /** read a number into name and set base + */ + protected def getNumber:unit = { + while (in.digit2int(in.ch, if (base < 10) 10 else base) >= 0) { + putChar(in.ch); + in.next; + } + token = INTLIT; + if (base <= 10 && in.ch == '.') { + putChar(in.ch); + in.next; + getFraction + } else if (base <= 10 && + (in.ch == 'e' || in.ch == 'E' || + in.ch == 'f' || in.ch == 'F' || + in.ch == 'd' || in.ch == 'D')) { + getFraction + } else { + setName; + if (in.ch == 'l' || in.ch == 'L') { + in.next; + token = LONGLIT; + } + } + } + +// XML lexing---------------------------------------------------------------- + +/* + // start XML tokenizing methods + // prod. [i] refers to productions in http://www.w3.org/TR/REC-xml + + /** calls nextToken, starting the scanning of Scala tokens, + * after XML tokens. + */ + def xSync = { + token = SEMI; // avoid getting SEMI from nextToken if last was RBRACE + //in.next; + nextToken(); + } + + def xSync2 = fetchToken(); + + def xLookahead = srcIterator.lookahead1; + + /** read the next character. do not skip whitespace. + * treat CR LF as single LF. update ccol and cline + * + * @todo: may XML contain SU, in CDATA sections ? + */ + def xNext = { + lastpos = pos; + ch = srcIterator.raw; ccol = ccol + 1; // = in.next without unicode + ch match { + case SU => + syntaxError(lastpos, "unclosed XML literal"); + token = EOF; + case LF => + ccol = 0; cline = cline + 1; + case CR => + if (LF == srcIterator.lookahead1) { + srcIterator.raw; ccol = 0; cline = cline + 1; + } + case _ => + //Console.print(ch.asInstanceOf[char]); // DEBUG + } + pos = Position.encode(cline, ccol); + //Console.print(ch); + } + + final val LT = Name.fromString("<"); + + def xStartsXML = { + /* unit.global.xmlMarkup && */ (token == IDENTIFIER) &&(name == LT); + /* || // support for proc instr, cdata, comment... ? + {val s = name.toString(); + s.charAt(0) == '<' && (s.charAt(1)=='?' || s.charAt(1)=='!')}) */ + } + + // end XML tokenizing + +*/ +// Errors ----------------------------------------------------------------- + + /** 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); + +// Keywords ----------------------------------------------------------------- + + /** Keyword array; maps from name indices to tokens */ + private var key: Array[byte] = _; + private var maxKey = 0; + private var tokenName = new Array[Name](128); + + { + var tokenCount = 0; + + // Enter keywords + + def enterKeyword(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 = newTermName(s); + tokenName(tokenId) = n; + if (n.start > maxKey) maxKey = n.start; + if (tokenId >= tokenCount) tokenCount = tokenId + 1; + } + + 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("<%", VIEWBOUND); + enterKeyword("#", HASH); + enterKeyword("@", AT); + + // Build keyword array + key = new Array[byte](maxKey+1); + for (val i <- Iterator.range(0, maxKey + 1)) + key(i) = IDENTIFIER; + for (val j <- Iterator.range(0, tokenCount)) + if (tokenName(j) != null) + key(tokenName(j).start) = j.asInstanceOf[byte]; + + } + +// Token representation ----------------------------------------------------- + + /** Convert name to token */ + def name2token(name: Name): int = + if (name.start <= maxKey) key(name.start) else IDENTIFIER; + + /** Returns the string representation of given token. */ + def token2string(token: int): String = token match { + case IDENTIFIER => + "identifier"/* + \""+name+"\""*/ + case CHARLIT => + "character literal" + case INTLIT => + "integer literal" + case LONGLIT => + "long literal" + case FLOATLIT => + "float literal" + case DOUBLELIT => + "double literal" + case STRINGLIT => + "string literal" + case SYMBOLLIT => + "symbol literal" + case LPAREN => + "'('" + case RPAREN => + "')'" + case LBRACE => + "'{'" + case RBRACE => + "'}'" + case LBRACKET => + "'['" + case RBRACKET => + "']'" + case EOF => + "eof" + case ERROR => + "something" + case SEMI => + "';'" + case COMMA => + "','" + case CASECLASS => + "case class" + case CASEOBJECT => + "case object" + case _ => + try { + "'" + tokenName(token) + "'" + } catch { + case _: ArrayIndexOutOfBoundsException => + "'<" + token + ">'" + case _: NullPointerException => + "'<(" + token + ")>'" + } + } + + override def toString() = token match { + case IDENTIFIER => + "id(" + name + ")" + case CHARLIT => + "char(" + intVal + ")" + case INTLIT => + "int(" + intVal + ")" + case LONGLIT => + "long(" + intVal + ")" + case FLOATLIT => + "float(" + floatVal + ")" + case DOUBLELIT => + "double(" + floatVal + ")" + case STRINGLIT => + "string(" + name + ")" + case SEMI => + ";" + case COMMA => + "," + case _ => + token2string(token) + } + + /** INIT: read lookahead character and token. + */ + in.next; + nextToken(); + } +} diff --git a/sources/scala/tools/nsc/ast/parser/ParserPhase.scala b/sources/scala/tools/nsc/ast/parser/ParserPhase.scala new file mode 100644 index 0000000000..dab3581355 --- /dev/null +++ b/sources/scala/tools/nsc/ast/parser/ParserPhase.scala @@ -0,0 +1,11 @@ +package scala.tools.nsc.ast.parser; + +abstract class ParserPhase(prev: Phase) + extends StdPhase(prev) + with Lexical + with Syntactic { + def name = "parser"; + def apply(unit: global.CompilationUnit): unit = { + unit.body = new Parser(unit).parse(); + } +} diff --git a/sources/scala/tools/nsc/ast/parser/Syntactic.scala b/sources/scala/tools/nsc/ast/parser/Syntactic.scala new file mode 100755 index 0000000000..6922adc862 --- /dev/null +++ b/sources/scala/tools/nsc/ast/parser/Syntactic.scala @@ -0,0 +1,1793 @@ +package scala.tools.nsc.ast.parser; + +import scala.tools.util.Position; +import scala.collection.mutable.ListBuffer; +import symtab.Flags; +import Tokens._; + +abstract class Syntactic: ParserPhase { + + import global._; + import posAssigner.atPos; + + class Parser(unit: CompilationUnit) { + + val in = new Scanner(unit); + + /** the markup parser + val xmlp = new MarkupParser(unit, s, this, false); + */ + + /** The current nesting depths of while and do loops. + */ + var loopNestingDepth = 0; + + /** this is the general parse method + */ + def parse(): List[Tree] = { + val ts = compilationUnit(); + accept(EOF); + ts + } + +/////// ERROR HANDLING ////////////////////////////////////////////////////// + + private def skip(): unit = { + //System.out.println("<skipping> " + in.token2string(in.token));//DEBUG + var nparens = 0; + var nbraces = 0; + while (true) { + in.token match { + case EOF => + return; + case SEMI => + if (nparens == 0 && nbraces == 0) return; + case RPAREN => + nparens = nparens - 1; + case RBRACE => + if (nbraces == 0) return; + nbraces = nbraces - 1; + case LPAREN => + nparens = nparens + 1; + case LBRACE => + nbraces = nbraces + 1; + case _ => + } + in.nextToken(); + } + } + + def syntaxError(msg: String, skipIt: boolean): unit = + syntaxError(in.pos, msg, skipIt); + + def syntaxError(pos: int, msg: String, skipIt: boolean): unit = { + if (pos != in.errpos) { + unit.error(pos, msg); + in.errpos = pos; + } + if (skipIt) skip(); + } + + def accept(token: int): int = { + val pos = in.pos; + if (in.token != token) + syntaxError( + if (Position.line(in.pos) > Position.line(in.lastpos)) in.lastpos + else in.pos, + in.token2string(token) + " expected but " + + in.token2string(in.token) + " found.", true); + if (in.token == token) in.nextToken(); + pos + } + + def errorTypeTree = GeneralTypeTree().setType(ErrorType).setPos(in.pos); + def errorTermTree = Literal(null).setPos(in.pos); + def errorPatternTree = Ident(nme.WILDCARD).setPos(in.pos); + +/////// TOKEN CLASSES ////////////////////////////////////////////////////// + + def isModifier: boolean = in.token match { + case ABSTRACT | FINAL | SEALED | PRIVATE | PROTECTED | OVERRIDE => true + case _ => false + } + + def isLocalModifier: boolean = in.token match { + case ABSTRACT | FINAL | SEALED => true + case _ => false + } + + def isDefIntro: boolean = in.token match { + case VAL | VAR | DEF | TYPE | OBJECT | + CASEOBJECT | CLASS | CASECLASS | TRAIT => true + case _ => false + } + + def isDclIntro: boolean = in.token match { + case VAL | VAR | DEF | TYPE => true + case _ => false + } + + def isExprIntro: boolean = in.token match { + case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | + STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL | IDENTIFIER | + THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE | + DO | RETURN | THROW | LPAREN | LBRACE => true + case _ => false + } + +/////// COMMENT AND ATTRIBUTE COLLECTION ////////////////////////////////////// + + /** Join the comment associated with a definition + */ + def joinComment(def trees: List[Tree]): List[Tree] = { + val buf = in.docBuffer; + if (buf != null) { + in.docBuffer = null; + trees map (t => DocDef(buf.toString(), t) setPos t.pos) + } else trees + } + +/////// TREE CONSTRUCTION //////////////////////////////////////////////////// + + def fresh(): Name = unit.fresh.newName("x"); + + /** Create a tree representing a packaging + */ + def makePackaging(pkg: Tree, stats: List[Tree]): Tree = + atPos(in.pos) { + pkg match { + case Ident(name) => + PackageDef(pkg, stats) + case Select(qual, name) => + makePackaging(qual, List(PackageDef(Ident(name), stats))) + } + } + + /** Create tree representing binary operation expression or pattern. + */ + def makeBinop(isExpr: boolean, left: Tree, op: Name, right: Tree): Tree = { + if (isExpr) { + if (isLeftAssoc(op)) { + Apply(Select(left, op.encode), List(right)) + } else { + val x: Name = fresh(); + Block( + List(ValDef(0, x, EmptyTree, left)), + Apply(Select(right, op.encode), List(Ident(x)))) + } + } else { + Apply(Ident(op.encode.toTypeName), List(left, right)) + } + } + def makeAlternative(ts: List[Tree]): Tree = { + def alternatives(t: Tree): List[Tree] = t match { + case Alternative(ts) => ts + case _ => List(t) + } + Alternative(for (val t <- ts; val a <- alternatives(t)) yield a) + } + + def makeSequence(ts: List[Tree]): Tree = { + def elements(t: Tree): List[Tree] = t match { + case Sequence(ts) => ts + case _ => List(t) + } + Sequence(for (val t <- ts; val e <- elements(t)) yield e) + } + + def scalaDot(name: Name): Tree = + Select(Ident(nme.scala), name); + def scalaRuntimeDot(name: Name): Tree = + Select(scalaDot(nme.runtime), name); + def ScalaRunTimeDot(name: Name): Tree = + Select(scalaRuntimeDot(nme.ScalaRunTime), name); + def scalaBooleanDot(name: Name): Tree = + Select(scalaDot(nme.Boolean), name); + def scalaAnyRefConstr(): Tree = + Apply(scalaDot(nme.AnyRef.toTypeName), List()); + def scalaObjectConstr(): Tree = + Apply(scalaDot(nme.ScalaObject.toTypeName), List()); + def caseClassConstr(): Tree = + Apply(scalaDot(nme.CaseClass.toTypeName), List()); + + def makeWhile(lname: Name, cond: Tree, body: Tree): Tree = { + val continu = Apply(Ident(lname), List()); + val rhs = If(cond, Block(List(body), continu), Literal(())); + LabelDef(lname, Nil, rhs) + } + + def makeDoWhile(lname: Name, body: Tree, cond: Tree): Tree = { + val continu = Apply(Ident(lname), List()); + val rhs = Block(List(body), If(cond, continu, Literal(()))); + LabelDef(lname, Nil, rhs) + } + + def makeBlock(stats: List[Tree]): Tree = { + if (stats.isEmpty) Literal(()) + else if (!stats.last.isTerm) Block(stats, Literal(())); + else if (stats.length == 1) stats(0) + else Block(stats.init, stats.last) + } + + /** Convert tree to formal parameter list + */ + def convertToParams(t: Tree): List[ValDef] = t match { + case Function(params, EmptyTree) => + params + case Ident(_) | Typed(Ident(_), _) => + List(convertToParam(t)); + case Literal(x) if x == () => //todo: check with Literal(()) + Nil + case _ => + syntaxError(t.pos, "malformed formal parameter list", false); + Nil + } + + /** Convert tree to formal parameter + */ + def convertToParam(tree: Tree): ValDef = + atPos(tree.pos) { + tree match { + case Ident(name) => + ValDef(Flags.PARAM, name, EmptyTree, EmptyTree) + case Typed(Ident(name), tpe) => + ValDef(Flags.PARAM, name, tpe, EmptyTree) + case _ => + syntaxError(tree.pos, "not a legal formal parameter", false); + ValDef(Flags.PARAM, nme.ERROR, errorTypeTree, EmptyTree) + } + } + + /** Convert (qual)ident to type identifier + */ + def convertToTypeId(tree: Tree): Tree = tree match { + case Ident(name) => + Ident(name.toTypeName).setPos(tree.pos) + case Select(qual, name) => + Select(qual, name.toTypeName).setPos(tree.pos) + case _ => + System.out.println(tree);//debug + syntaxError(tree.pos, "identifier expected", false); + errorTypeTree + } + + /** Complete unapplied constructor with `()' arguments + */ + def applyConstr(t: Tree): Tree = t match { + case Apply(_, _) => t + case _ => Apply(t, List()) setPos t.pos + } + + /** make closure from tree */ + def makeClosure(tree: Tree): Tree = { + val pname = fresh(); + def insertParam(tree: Tree): Tree = tree match { + case Ident(name) => + Select(Ident(pname), name) + case Select(qual, name) => + Select(insertParam(qual), name) + case Apply(fn, args) => + Apply(insertParam(fn), args) + case TypeApply(fn, args) => + TypeApply(insertParam(fn), args) + case _ => + syntaxError(tree.pos, "cannot convert to closure", false); + errorTermTree + } + Function( + List(ValDef(Flags.PARAM, pname, EmptyTree, EmptyTree)), + insertParam(tree)) + } + +/////// OPERAND/OPERATOR STACK ///////////////////////////////////////////////// + + case class OpInfo(operand: Tree, operator: Name, pos: int); + var opstack: List[OpInfo] = Nil; + + def precedence(operator: Name): int = + if (operator eq nme.ERROR) -1 + else { + val firstCh = operator(0); + if (((firstCh >= 'A') && (firstCh <= 'Z')) || + ((firstCh >= 'a') && (firstCh <= 'z'))) + 1 + else + firstCh match { + case '|' => 2 + case '^' => 3 + case '&' => 4 + case '<' | '>' => 5 + case '=' | '!' => 6 + case ':' => 7 + case '+' | '-' => 8; + case '*' | '/' | '%' => 9; + case _ => 10; + } + } + + def isLeftAssoc(operator: Name): boolean = + operator.length > 0 && operator(operator.length - 1) != ':'; + + def reduceStack(isExpr: boolean, base: List[OpInfo], top0: Tree, prec: int, leftAssoc: boolean): Tree = { + var top = top0; + if (opstack != base && + precedence(opstack.head.operator) == prec && + isLeftAssoc(opstack.head.operator) != leftAssoc) { + syntaxError( + opstack.head.pos, + "left- and right-associative operators with same precedence may not be mixed", + false); + } + while (opstack != base && + (prec < precedence(opstack.head.operator) || + (leftAssoc && prec == precedence(opstack.head.operator)))) { + top = atPos(opstack.head.pos) { + makeBinop(isExpr, opstack.head.operand, opstack.head.operator, top) + } + opstack = opstack.tail; + } + top + } + +/////// IDENTIFIERS AND LITERALS //////////////////////////////////////////////////////////// + + final val MINUS: Name = "-"; + final val PLUS : Name = "+"; + final val BANG : Name = "!"; + final val TILDE: Name = "~"; + final val STAR : Name = "*"; + final val BAR : Name = "|"; + final val OPT : Name = "?"; + final val LT : Name = "<"; + + def ident(): Name = + if (in.token == IDENTIFIER) { + val name = in.name.encode; + in.nextToken(); + name + } else { + accept(IDENTIFIER); + nme.ERROR + } + + /** StableRef ::= StableId + * | [Ident `.'] this + * SimpleType ::= StableRef [`.' type] + */ + def stableRef(thisOK: boolean, typeOK: boolean): Tree = { + var t: Tree = null; + if (in.token == THIS) { + t = atPos(in.skipToken()) { This(nme.EMPTY.toTypeName) } + if (!thisOK || in.token == DOT) + t = atPos(accept(DOT)) { selectors(t, typeOK) } + } else if (in.token == SUPER) { + t = atPos(in.skipToken()) { + Super(nme.EMPTY.toTypeName, mixinQualifierOpt()) + } + t = atPos(accept(DOT)) { Select(t, ident()) } + if (in.token == DOT) + t = atPos(in.skipToken()) { selectors(t, typeOK) } + } else { + val i = atPos(in.pos) { Ident(ident()) } + t = i; + if (in.token == DOT) { + val pos = in.skipToken(); + if (in.token == THIS) { + in.nextToken(); + t = atPos(i.pos) { This(i.name.toTypeName) } + if (!thisOK || in.token == DOT) + t = atPos(accept(DOT)) { selectors(t, typeOK) } + } else if (in.token == SUPER) { + in.nextToken(); + t = atPos(i.pos) { Super(i.name.toTypeName, mixinQualifierOpt()) } + t = atPos(accept(DOT)) { Select(t, ident())} + if (in.token == DOT) + t = atPos(in.skipToken()) { selectors(t, typeOK) } + } else { + t = atPos(pos) { selectors(t, typeOK) } + } + } + } + t + } + + def selectors(t: Tree, typeOK: boolean): Tree = + if (typeOK && in.token == TYPE) { + in.nextToken(); + SingletonTypeTree(t) + } else { + val t1 = Select(t, ident()); + if (in.token == DOT) atPos(in.skipToken()) { selectors(t1, typeOK) } + else t1 + } + + /** MixinQualifier ::= `[' Id `]' + */ + def mixinQualifierOpt(): Name = + if (in.token == LBRACKET) { + in.nextToken(); + val name = ident().toTypeName; + accept(RBRACKET); + name + } else { + nme.EMPTY.toTypeName + } + + /** StableId ::= Id + * | StableRef `.' Id + * | [Id '.'] super [MixinQualifier] ` `.' Id + */ + def stableId(): Tree = + stableRef(false, false); + + /** QualId ::= Id {`.' Id} + */ + def qualId(): Tree = { + val id = atPos(in.pos) { Ident(ident()) } + if (in.token == DOT) atPos(in.skipToken()) { selectors(id, false) } + else id + } + + /** SimpleExpr ::= literal + * | symbol [ArgumentExprs] + * | null + */ + def literal(isPattern: boolean, isNegated: boolean): Tree = { + def litToTree() = atPos(in.pos) { + Literal( + in.token match { + case CHARLIT => + in.intVal.asInstanceOf[char] + case INTLIT => + in.intVal(isNegated).asInstanceOf[int] + case LONGLIT => + in.intVal(isNegated) + case FLOATLIT => + in.floatVal(isNegated).asInstanceOf[float] + case DOUBLELIT => + in.floatVal(isNegated) + case STRINGLIT | SYMBOLLIT => + in.name.toString() + case TRUE => + true + case FALSE => + false + case NULL => + null + case _ => + syntaxError("illegal literal", true); + null + }) + } + + val isSymLit = in.token == SYMBOLLIT; + val t = litToTree(); + val pos = in.skipToken(); + if (isSymLit) { + atPos(pos) { + var symid = scalaDot(nme.Symbol); + if (isPattern) { symid = convertToTypeId(symid) } + Apply(symid, List(t)) + } + } else { + t + } + } + +//////// TYPES /////////////////////////////////////////////////////////////// + + /** TypedOpt ::= [`:' Type] + */ + def typedOpt(): Tree = + if (in.token == COLON) { in.nextToken(); typ() } + else EmptyTree; + + /** SimpleTypedOpt ::= [`:' SimpleType] + */ + def simpleTypedOpt(): Tree = + if (in.token == COLON) { in.nextToken(); simpleType() } + else EmptyTree; + + /** Types ::= Type {`,' Type} + */ + def types(): List[Tree] = { + val ts = new ListBuffer[Tree] + typ(); + while (in.token == COMMA) { + in.nextToken(); + ts + typ(); + } + ts.toList + } + + /** Type ::= Type1 `=>' Type + * | `(' [Types] `)' `=>' Type + * | Type1 + */ + def typ(): Tree = { + val t = + if (in.token == LPAREN) { + in.nextToken(); + if (in.token == RPAREN) { + in.nextToken(); + atPos(accept(ARROW)) { FunctionTypeTree(List(), typ()) } + } else { + val t0 = typ(); + if (in.token == COMMA) { + in.nextToken(); + val ts = new ListBuffer[Tree] + t0 ++ types(); + accept(RPAREN); + atPos (accept(ARROW)) { FunctionTypeTree(ts.toList, typ()) } + } else { + accept(RPAREN); t0 + } + } + } else { + type1() + } + if (in.token == ARROW) atPos(in.skipToken()) { + FunctionTypeTree(List(t), typ()) } + else t + } + + /** Type1 ::= SimpleType {with SimpleType} [Refinement] + */ + def type1(): Tree = { + val pos = in.pos; + var t = simpleType(); + if (in.token == WITH) { + val ts = new ListBuffer[Tree] + t; + while (in.token == WITH) { + in.nextToken(); ts + simpleType() + } + t = atPos(pos) { IntersectionTypeTree(ts.toList) } + } + if (in.token == LBRACE) + t = atPos(pos) { RefinementTypeTree(t, refinement()) } + t + } + + /** SimpleType ::= SimpleType TypeArgs + * | SimpleType `#' Id + * | StableId + * | StableRef `.' type + * | `(' Type `)' + */ + def simpleType(): Tree = { + val pos = in.pos; + var t: Tree = + if (in.token == LPAREN) { + in.nextToken(); + val t = typ(); + accept(RPAREN); + t + } else { + val r = stableRef(false, true); + r match { + case SingletonTypeTree(_) => r + case _ => convertToTypeId(r); + } + } + while (true) { + if (in.token == HASH) + t = atPos(in.skipToken()) { + SelectFromTypeTree(t, ident().toTypeName) + } + else if (in.token == LBRACKET) + t = atPos(pos) { AppliedTypeTree(t, typeArgs()) } + else + return t + } + null; //dummy + } + + /** TypeArgs ::= `[' Types `]' + */ + def typeArgs(): List[Tree] = { + accept(LBRACKET); + val ts = types(); + accept(RBRACKET); + ts + } + +//////// EXPRESSIONS //////////////////////////////////////////////////////// + + /** EqualsExpr ::= `=' Expr + */ + def equalsExpr(): Tree = { + accept(EQUALS); + expr() + } + + /** Exprs ::= Expr {`,' Expr} [ `:' `_' `*' ] + */ + def exprs(): List[Tree] = { + val ts = new ListBuffer[Tree] + expr(true, false); + while (in.token == COMMA) { + in.nextToken(); ts + expr(true, false) + } + ts.toList + } + + /** Expr ::= Bindings `=>' Expr + * | Expr1 + * ResultExpr ::= Bindings `=>' Block + * | Expr1 + * Expr1 ::= (' 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 + * | `.' SimpleExpr + * | PostfixExpr [`:' Type1] + * Bindings ::= Id [`:' Type1] + * | `(' [Binding {`,' Binding}] `)' + * Binding ::= Id [`:' Type] + */ + + def expr(): Tree = + expr(false, false); + + def expr(isArgument: boolean, isInBlock: boolean): Tree = { + if (in.token == IF) { + val pos = in.skipToken(); + accept(LPAREN); + val cond = expr(); + accept(RPAREN); + val thenp = expr(); + val elsep = + if (in.token == ELSE) { in.nextToken(); expr() } + else EmptyTree; + atPos(pos) { If(cond, thenp, elsep) } + } else if (in.token == TRY) { + atPos(in.skipToken()) { + accept(LBRACE); + val body = block(); + accept(RBRACE); + val catcher = + if (in.token == CATCH) { in.nextToken(); expr() } + else EmptyTree; + val finalizer = + if (in.token == FINALLY) { in.nextToken(); expr() } + else EmptyTree; + Try(body, catcher, finalizer) + } + } else if (in.token == WHILE) { + val lname: Name = "label$" + loopNestingDepth; + loopNestingDepth = loopNestingDepth + 1; + val pos = in.skipToken(); + accept(LPAREN); + val cond = expr(); + accept(RPAREN); + val body = expr(); + loopNestingDepth = loopNestingDepth - 1; + atPos(pos) { makeWhile(lname, cond, body) } + } else if (in.token == DO) { + val lname: Name = "label$" + loopNestingDepth; + loopNestingDepth = loopNestingDepth + 1; + val pos = in.skipToken(); + val body = expr(); + if (in.token == SEMI) in.nextToken(); + accept(WHILE); + accept(LPAREN); + val cond = expr(); + accept(RPAREN); + loopNestingDepth = loopNestingDepth - 1; + atPos(pos) { makeDoWhile(lname, body, cond) } + } else if (in.token == FOR) { + atPos(in.skipToken()) { + accept(LPAREN); + val enums = enumerators(); + accept(RPAREN); + if (in.token == YIELD) { + in.nextToken(); For(enums, expr(), true) + } else For(enums, expr(), false) + } + } else if (in.token == RETURN) { + atPos(in.skipToken()) { + Return(if (isExprIntro) expr() else Literal(())) + } + } else if (in.token == THROW) { + atPos(in.skipToken()) { + Throw(expr()) + } + } else if (in.token == DOT) { + atPos(in.skipToken()) { + if (in.token == IDENTIFIER) makeClosure(simpleExpr()) + else { syntaxError("identifier expected", true); errorTermTree } + } + } else { + var t = postfixExpr(); + if (in.token == EQUALS) { + t match { + case Ident(_) | Select(_, _) | Apply(_, _) => + t = atPos(in.skipToken()) { Assign(t, expr()) } + case _ => + } + } else if (in.token == COLON) { + val pos = in.skipToken(); + if (isArgument && in.token == USCORE) { + val pos1 = in.skipToken(); + if (in.token == IDENTIFIER && in.name == nme.STAR) { + in.nextToken(); + t = atPos(pos) { + Typed(t, atPos(pos1) { Ident(nme.WILDCARD_STAR.toTypeName) }) + } + } else { + syntaxError(in.pos, "`*' expected", true); + } + } else { + t = atPos(pos) { Typed(t, type1()) } + } + } + if (in.token == ARROW) { + t = atPos(in.skipToken()) { + Function(convertToParams(t), if (isInBlock) block() else expr()) + } + } + t + } + } + + /** PostfixExpr ::= [`.'] InfixExpr [Id] + * InfixExpr ::= PrefixExpr + * | InfixExpr Id InfixExpr + */ + def postfixExpr(): Tree = { + val base = opstack; + var top = prefixExpr(); + while (in.token == IDENTIFIER) { + top = reduceStack( + true, base, top, precedence(in.name), isLeftAssoc(in.name)); + opstack = OpInfo(top, in.name, in.pos) :: opstack; + ident(); + if (isExprIntro) { + top = prefixExpr(); + } else { + val topinfo = opstack.head; + opstack = opstack.tail; + return Select( + reduceStack(true, base, topinfo.operand, 0, true), + topinfo.operator.encode).setPos(topinfo.pos); + } + } + reduceStack(true, base, top, 0, true) + } + + /** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr + */ + def prefixExpr(): Tree = + if (in.token == IDENTIFIER && in.name == MINUS) { + val name = ident(); + in.token match { + case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => literal(false, true) + case _ => atPos(in.pos) { Select(simpleExpr(), name) } + } + } else if (in.token == IDENTIFIER && (in.name == PLUS || in.name == TILDE || in.name == BANG)) { + val pos = in.pos; + val name = ident(); + atPos(pos) { Select(simpleExpr(), name) } + } else { + simpleExpr() + } + + /* SimpleExpr ::= literal + * | xLiteral + * | StableRef + * | `(' [Expr] `)' + * | BlockExpr + * | new Template + * | SimpleExpr `.' Id + * | SimpleExpr TypeArgs + * | SimpleExpr ArgumentExprs + */ + def simpleExpr(): Tree = { + var t: Tree = _; + in.token match { + case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | + SYMBOLLIT | TRUE | FALSE | NULL => + t = literal(false, false); + case IDENTIFIER | THIS | SUPER => + t = /*if (s.xStartsXML) xmlp.xLiteral else*/ stableRef(true, false); + case LPAREN => + val pos = in.skipToken(); + if (in.token == RPAREN) { + in.nextToken(); + t = Literal(()).setPos(pos); + } else { + t = expr(); + if (in.token == COMMA) { + val commapos = in.skipToken(); + val ts = new ListBuffer[Tree] + t ++ exprs(); + accept(RPAREN); + if (in.token == ARROW) { + t = atPos(pos) { + Function(ts.toList map convertToParam, EmptyTree) + } + } else { + syntaxError(commapos, "`)' expected", false); + } + } else { + accept(RPAREN); + } + } + case LBRACE => + t = blockExpr() + case NEW => + t = atPos(in.skipToken()) { + val templ = template(); + New(if (templ.parents.length == 1 && templ.body.isEmpty) templ.parents.head + else templ) + } + case _ => + syntaxError("illegal start of simple expression", true); + t = errorTermTree + } + while (true) { + in.token match { + case DOT => + t = atPos(in.skipToken()) { Select(t, ident()) } + case LBRACKET => + t match { + case Ident(_) | Select(_, _) => + t = atPos(in.pos) { TypeApply(t, typeArgs()) } + case _ => + return t; + } + case LPAREN | LBRACE => + t = atPos(in.pos) { Apply(t, argumentExprs()) } + case _ => + return t + } + } + null;//dummy + } + + /** ArgumentExprs ::= `(' [Exprs] `)' + * | BlockExpr + */ + def argumentExprs(): List[Tree] = { + if (in.token == LBRACE) { + List(blockExpr()) + } else { + accept(LPAREN); + val ts = if (in.token == RPAREN) List() else exprs(); + accept(RPAREN); + ts + } + } + + /** BlockExpr ::= `{' CaseClause {CaseClause} `}' + * | `{' Block `}' + */ + def blockExpr(): Tree = { + val res = + atPos(accept(LBRACE)) { + if (in.token == CASE) { + var stats: List[CaseDef] = List(); + do { + stats = caseClause() :: stats; + } while (in.token == CASE); + Visitor(stats.reverse) + } else { + block() + } + } + accept(RBRACE); + res + } + + /** Block ::= BlockStatSeq + */ + def block(): Tree = makeBlock(blockStatSeq(new ListBuffer[Tree])); + + /** caseClause : =>= case Pattern [if PostfixExpr] `=>' Block + */ + def caseClause(): CaseDef = + atPos(accept(CASE)) { + val pat = pattern(); + val guard = + if (in.token == IF) { in.nextToken(); postfixExpr() } + else EmptyTree; + CaseDef(pat, guard, atPos(accept(ARROW))(block())) + } + + /** Enumerators ::= Generator {`;' Enumerator} + * Enumerator ::= Generator + * | Expr + */ + def enumerators(): List[Tree] = { + val enums = new ListBuffer[Tree] + generator(); + while (in.token == SEMI) { + in.nextToken(); + enums + (if (in.token == VAL) generator() else expr()) + } + enums.toList + } + + /** Generator ::= val Pattern1 `<-' Expr + */ + def generator(): Tree = + atPos(accept(VAL)) { + PatDef(0, pattern1(false), { accept(LARROW); expr() }) + } + +//////// PATTERNS //////////////////////////////////////////////////////////// + + /** Patterns ::= SeqPattern { `,' SeqPattern } + */ + def patterns(): List[Tree] = { + val ts = new ListBuffer[Tree]; + ts + pattern(true); + while (in.token == COMMA) { + in.nextToken(); ts + pattern(true); + } + ts.toList + } + + /** Pattern ::= Pattern1 { `|' Pattern1 } + * SeqPattern ::= SeqPattern1 { `|' SeqPattern1 } + */ + def pattern(seqOK: boolean): Tree = { + val pos = in.pos; + val t = pattern1(seqOK); + if (in.token == IDENTIFIER && in.name == BAR) { + val ts = new ListBuffer[Tree] + t; + while (in.token == IDENTIFIER && in.name == BAR) { + in.nextToken(); ts + pattern1(seqOK); + } + atPos(pos) { makeAlternative(ts.toList) } + } else t + } + + def pattern(): Tree = pattern(false); + + /** Pattern1 ::= varid `:' Type1 + * | `_' `:' Type1 + * | Pattern2 + * SeqPattern1 ::= varid `:' Type1 + * | `_' `:' Type1 + * | [SeqPattern2] + */ + def pattern1(seqOK: boolean): Tree = + if (seqOK && !isExprIntro) { + atPos(in.pos) { Sequence(List()) } + } else { + val p = pattern2(seqOK); + if (in.token == COLON && treeInfo.isVarPattern(p)) + atPos(in.skipToken()) { Typed(p, type1()) } + else p + } + + /* Pattern2 ::= varid [ @ Pattern3 ] + * | Pattern3 + * SeqPattern2 ::= varid [ @ SeqPattern3 ] + * | SeqPattern3 + */ + def pattern2(seqOK: boolean): Tree = { + val p = pattern3(seqOK); + if (in.token == AT) { + p match { + case Ident(name) => + if (name == nme.WILDCARD) { + in.nextToken(); pattern3(seqOK) + } else if (treeInfo.isVariableName(name)) { + atPos(in.skipToken()) { Bind(name, pattern3(seqOK)) } + } else { + p + } + case _ => + p + } + } else p + } + + /* Pattern3 ::= SimplePattern + * | SimplePattern {Id SimplePattern} + * SeqPattern3 ::= SeqSimplePattern [ '*' | '?' | '+' ] + * | SeqSimplePattern {Id SeqSimplePattern} + */ + def pattern3(seqOK: boolean): Tree = { + val base = opstack; + var top = simplePattern(seqOK); + if (seqOK && in.token == IDENTIFIER) { + if (in.name == STAR) { /* p* becomes z@( |(p,z)) */ + return atPos(in.skipToken()) { + val zname = fresh(); + Bind( + zname, + makeAlternative(List( + Sequence(List()), makeSequence(List(top, Ident(zname)))))) + } + } else if (in.name == PLUS) { /* p+ becomes z@(p,(z| )) */ + return atPos(in.skipToken()) { + val zname = fresh(); + Bind( + zname, + makeSequence(List( + top, makeAlternative(List(Ident(zname), Sequence(List())))))) + } + } else if (in.name == OPT) { /* p? becomes (p| ) */ + return atPos(in.skipToken()) { + makeAlternative(List(top, Sequence(List()))) + } + } + } + while (in.token == IDENTIFIER && in.name != BAR) { + top = reduceStack( + false, base, top, precedence(in.name), isLeftAssoc(in.name)); + opstack = OpInfo(top, in.name, in.pos) :: opstack; + ident(); + top = simplePattern(seqOK) + } + reduceStack(false, base, top, 0, true) + } + + /** SimplePattern ::= varid + * | `_' + * | literal + * | `<' xLiteralPattern + * | StableId [ `(' Patterns `)' ] + * | `(' [Pattern] `)' + * SimpleSeqPattern ::= varid + * | `_' + * | literal + * | `<' xLiteralPattern + * | StableId [ `(' Patterns `)' ] + * | `(' Patterns `)' + */ + def simplePattern(seqOK: boolean): Tree = in.token match { + case IDENTIFIER | THIS => + var t = stableId(); + in.token match { + case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => + t match { + case Ident(name) if name == nme.MINUS => + return literal(true, true); + case _ => + } + case _ => + } + if (in.token == LPAREN) { + atPos(in.skipToken()) { + val ps = if (in.token == RPAREN) List() else patterns(); + accept(RPAREN); + Apply(convertToTypeId(t), ps) + } + } else t + case USCORE => + atPos(in.skipToken()) { Ident(nme.WILDCARD) } + case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => + literal(true, false) + case LPAREN => + val pos = in.skipToken(); + val p = + if (seqOK) atPos(pos) { makeSequence(patterns()) } + else if (in.token != RPAREN) pattern(false); + else Literal(()).setPos(pos); + accept(RPAREN); + p + case _ => + syntaxError("illegal start of simple pattern", true); + errorPatternTree + } + +////////// MODIFIERS //////////////////////////////////////////////////////////// + + /** Modifiers ::= {Modifier} + * Modifier ::= final + * | private + * | protected + * | override + * | abstract + */ + def modifiers(): int = { + def loop(mods: int): int = in.token match { + case ABSTRACT => + loop(addMod(mods, Flags.ABSTRACT)) + case FINAL => + loop(addMod(mods, Flags.FINAL)) + case SEALED => + loop(addMod(mods, Flags.SEALED)) + case PRIVATE => + loop(addMod(mods, Flags.PRIVATE)) + case PROTECTED => + loop(addMod(mods, Flags.PROTECTED)) + case OVERRIDE => + loop(addMod(mods, Flags.OVERRIDE)) + case _ => + mods + } + loop(0); + } + + /** LocalClassModifiers ::= {LocalClassModifier} + * LocalClassModifier ::= final + * | private + */ + def localClassModifiers(): int = { + def loop(mods: int): int = in.token match { + case ABSTRACT => + loop(addMod(mods, Flags.ABSTRACT)) + case FINAL => + loop(addMod(mods, Flags.FINAL)) + case SEALED => + loop(addMod(mods, Flags.SEALED)) + case _ => + mods + } + loop(0) + } + + private def addMod(mods: int, mod: int): int = { + if ((mods & mod) != 0) + syntaxError(in.pos, "repeated modifier", false); + in.nextToken(); + mods | mod; + } + +//////// PARAMETERS ////////////////////////////////////////////////////////// + + /** ParamClauses ::= {ParamClause} + */ + def paramClauses(): List[List[ValDef]] = { + val vds = new ListBuffer[List[ValDef]]; + while (in.token == LPAREN) vds + paramClause(false); + vds.toList + } + + /** ParamClauseOpt ::= [ParamClause] + */ + def paramClauseOpt(ofClass: boolean): List[List[ValDef]] = + if (in.token == LPAREN) List(paramClause(ofClass)) + else List(); + + /** ParamClause ::= `(' [Param {`,' Param}] `)' + * ClassParamClause ::= `(' [ClassParam {`,' ClassParam}] `)' + */ + def paramClause(ofClass: boolean): List[ValDef] = { + accept(LPAREN); + val params = new ListBuffer[ValDef]; + if (in.token != RPAREN) { + params + param(ofClass); + while (in.token == COMMA) { + in.nextToken(); params + param(ofClass) + } + } + accept(RPAREN); + params.toList + } + + /** Param ::= Id `:' ParamType + * ClassParam ::= [[modifiers] val] Param + */ + def param(ofClass: boolean): ValDef = { + atPos(in.pos) { + var mods = if (ofClass) modifiers() | Flags.PARAM else Flags.PARAM; + if (in.token == VAL) { + in.nextToken(); mods = mods | Flags.PARAMACCESSOR; + } else if (mods != Flags.PARAM) { + accept(VAL); + } + val name = ident(); + accept(COLON); + ValDef(mods, name, paramType(), EmptyTree) + } + } + + /** ParamType ::= Type | `=>' Type | Type `*' + */ + def paramType(): Tree = + if (in.token == ARROW) + atPos(in.skipToken()) { FunctionTypeTree(List(), typ()) } + else { + val t = typ(); + if (in.token == IDENTIFIER && in.name == STAR) { + in.nextToken(); + atPos(t.pos) { + AppliedTypeTree( + scalaDot(nme.REPEATED_PARAM_CLASS_NAME.toTypeName), List(t)) + } + } else t + } + + /** TypeParamClauseOpt ::= [`[' TypeParam {`,' TypeParam} `]'] + * FunTypeParamClauseOpt ::= [`[' FunTypeParam {`,' FunTypeParam} `]'] + */ + def typeParamClauseOpt(ofClass: boolean): List[AbsTypeDef] = { + val params = new ListBuffer[AbsTypeDef]; + if (in.token == LBRACKET) { + in.nextToken(); + params + typeParam(ofClass); + while (in.token == COMMA) { + in.nextToken(); + params + typeParam(ofClass); + } + accept(RBRACKET); + } + params.toList + } + + /** TypeParam ::= [`+' | `-'] FunTypeParam + * FunTypeParam ::= Id TypeBounds + */ + def typeParam(ofClass: boolean): AbsTypeDef = { + var mods = Flags.PARAM; + if (ofClass && in.token == IDENTIFIER) { + if (in.name == PLUS) { + in.nextToken(); + mods = mods | Flags.COVARIANT; + } else if (in.name == MINUS) { + in.nextToken(); + mods = mods | Flags.CONTRAVARIANT; + } + } + atPos(in.pos) { typeBounds(mods, ident()) } + } + + /** TypeBounds ::= [`>:' Type] [`<:' Type] [`<%' Type] + */ + def typeBounds(mods: int, name: Name): AbsTypeDef = { + def bound(tok: int, default: Name): Tree = + if (in.token == tok) { in.nextToken(); typ() } + else scalaDot(default.toTypeName); + AbsTypeDef(mods, name.toTypeName, + bound(SUPERTYPE, nme.All), + bound(SUBTYPE, nme.Any), + bound(VIEWBOUND, nme.Any)) + } + +//////// DEFS //////////////////////////////////////////////////////////////// + + /** Import ::= import ImportExpr {`,' ImportExpr} + */ + def importClause(): List[Tree] = { + accept(IMPORT); + val ts = new ListBuffer[Tree] + importExpr(); + while (in.token == COMMA) { + in.nextToken(); ts + importExpr(); + } + ts.toList + } + + /** ImportRef ::= StableId `.' (Id | `_' | ImportSelectors) + */ + def importExpr(): Tree = + atPos(in.pos) { + var t: Tree = null; + var pos = 0; + if (in.token == THIS) { + t = atPos(in.pos) { This(nme.EMPTY.toTypeName) } + t = atPos(accept(DOT)) { Select(t, ident()) } + pos = accept(DOT); + } else { + val i = atPos(in.pos) { Ident(ident()) } + pos = accept(DOT); + if (in.token == THIS) { + in.nextToken(); + t = atPos(i.pos) { This(i.name.toTypeName) } + t = atPos(accept(DOT)) { Select(t, ident()) } + pos = accept(DOT); + } else { + t = i; + } + } + def loop: Tree = + if (in.token == USCORE) { + in.nextToken(); + Import(t, List(nme.WILDCARD)) + } else if (in.token == LBRACE) { + Import(t, importSelectors()) + } else { + val name = ident(); + if (in.token == DOT) { + t = atPos(pos) { Select(t, name) } + pos = accept(DOT); + loop + } else { + Import(t, List(name, name)); + } + } + loop + } + + /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}' + */ + def importSelectors(): List[Name] = { + val names = new ListBuffer[Name]; + accept(LBRACE); + var isLast = importSelector(names); + while (!isLast && in.token == COMMA) { + in.nextToken(); + isLast = importSelector(names); + } + accept(RBRACE); + names.toList + } + + /** ImportSelector ::= Id [`=>' Id | `=>' `_'] + */ + def importSelector(names: ListBuffer[Name]): boolean = + if (in.token == USCORE) { + in.nextToken(); names + nme.WILDCARD; true + } else { + val name = ident(); + names + name; + if (in.token == ARROW) { + in.nextToken(); + if (in.token == USCORE) { + in.nextToken(); names + nme.WILDCARD; + } else { + names + ident() + } + } else { + names + name + } + false + } + + /** Def ::= val PatDef + * | var VarDef + * | def FunDef + * | type TypeDef + * | TmplDef + * Dcl ::= val ValDcl + * | var ValDcl + * | def FunDcl + * | type TypeDcl + */ + def defOrDcl(mods: int): List[Tree] = { + in.token match { + case VAL => + patDefOrDcl(mods); + case VAR => + varDefOrDcl(mods); + case DEF => + funDefOrDcl(mods); + case TYPE => + in.nextToken(); + List(typeDefOrDcl(mods)) + case _ => + tmplDef(mods) + } + } + + /** PatDef ::= Pattern2 {`,' Pattern2} [`:' Type] `=' Expr + * ValDcl ::= Id {`,' Id} `:' Type + */ + def patDefOrDcl(mods: int): List[Tree] = { + var newmods = mods; + var lhs = new ListBuffer[Tree]; + do { + in.nextToken(); + lhs + pattern2(false) + } while (in.token == COMMA); + val tp = typedOpt(); + val rhs = + if (tp == EmptyTree || in.token == EQUALS) equalsExpr() + else { + newmods = newmods | Flags.DEFERRED; + EmptyTree + } + for (val p <- lhs.toList) yield { + atPos(p.pos) { + p match { + case Ident(name) => + ValDef(mods, name, tp.duplicate, rhs.duplicate) + case _ => + if (rhs == EmptyTree) { + syntaxError(p.pos, "cannot defer pattern definition", false); + errorPatternTree + } else { + PatDef( + mods, + if (tp == EmptyTree) p else Typed(p, tp), + rhs.duplicate) + } + } + } + } + } + + /** VarDef ::= Id {`,' Id} [`:' Type] `=' Expr + * | Id {`,' Id} `:' Type `=' `_' + * VarDcl ::= Id {`,' Id} `:' Type + */ + def varDefOrDcl(mods: int): List[Tree] = { + var newmods = mods | Flags.MUTABLE; + val lhs = new ListBuffer[Pair[Int, Name]]; + do { + lhs + Pair(in.skipToken(), ident()) + } while (in.token == COMMA); + val tp = typedOpt(); + val rhs = if (tp == EmptyTree || in.token == EQUALS) { + accept(EQUALS); + if (tp != EmptyTree && in.token == USCORE) { + in.nextToken(); + EmptyTree + } else + expr(); + } else { + newmods = newmods | Flags.DEFERRED; + EmptyTree + } + lhs.toList map { case Pair(pos, name) => + ValDef(newmods, name, tp.duplicate, rhs.duplicate) setPos pos } + } + + /** FunDef ::= FunSig {`,' FunSig} `:' Type `=' Expr + * | this ParamClause `=' ConstrExpr + * FunDcl ::= FunSig {`,' FunSig} `:' Type + * FunSig ::= id [FunTypeParamClause] ParamClauses + */ + def funDefOrDcl(mods: int): List[Tree] = { + in.nextToken(); + if (in.token == THIS) + List( + atPos(in.skipToken()) { + val vparams = List(paramClause(false)); + accept(EQUALS); + DefDef( + mods, nme.CONSTRUCTOR, List(), vparams, EmptyTree, constrExpr()) + }) + else { + var newmods = mods; + val lhs = new ListBuffer[Tuple4[Int, Name, List[AbsTypeDef], List[List[ValDef]]]] + + Tuple4( + in.pos, ident(), typeParamClauseOpt(false), paramClauses()); + while (in.token == COMMA) + lhs + Tuple4( + in.skipToken(), ident(), typeParamClauseOpt(false), paramClauses()); + val restype = typedOpt(); + val rhs = + if (restype == EmptyTree || in.token == EQUALS) equalsExpr(); + else { + newmods = newmods | Flags.DEFERRED; + EmptyTree + } + for (val Tuple4(pos, name, tparams, vparams) <- lhs.toList) yield + DefDef(newmods, name, tparams, vparams, + restype.duplicate, rhs.duplicate) setPos pos + } + } + + /** ConstrExpr ::= SelfInvocation + * | `{' SelfInvocation {`;' BlockStat} `}' + * SelfInvocation ::= this ArgumentExpr + */ + def constrExpr(): Tree = + if (in.token == LBRACE) { + atPos(in.skipToken()) { + val statlist = new ListBuffer[Tree]; + statlist + selfInvocation(); + val stats = + if (in.token == SEMI) { in.nextToken(); blockStatSeq(statlist) } + else statlist.toList; + accept(RBRACE); + makeBlock(stats) + } + } else selfInvocation(); + + /** SelfInvocation ::= this ArgumentExprs + */ + def selfInvocation(): Tree = + atPos(accept(THIS)) { Apply(Ident(nme.CONSTRUCTOR), argumentExprs()) } + + /** TypeDef ::= Id `=' Type + * TypeDcl ::= Id TypeBounds + */ + def typeDefOrDcl(mods: int): Tree = + atPos(in.pos) { + val name = ident().toTypeName; + in.token match { + case LBRACKET => + val tparams = typeParamClauseOpt(true); + accept(EQUALS); + AliasTypeDef(mods, name, tparams, typ()) + case EQUALS => + in.nextToken(); + AliasTypeDef(mods, name, List(), typ()) + case SUPERTYPE | SUBTYPE | VIEWBOUND | SEMI | COMMA | RBRACE => + typeBounds(mods | Flags.DEFERRED, name) + case _ => + syntaxError("`=', `>:', or `<:' expected", true); + EmptyTree + } + } + + /** TmplDef ::= ([case] class | trait) ClassDef + * | [case] object ObjectDef + */ + def tmplDef(mods: int): List[Tree] = in.token match { + case TRAIT => + classDef(mods | Flags.TRAIT | Flags.ABSTRACT); + case CLASS => + classDef(mods); + case CASECLASS => + classDef(mods | Flags.CASE); + case OBJECT => + objectDef(mods); + case CASEOBJECT => + objectDef(mods | Flags.CASE); + case _ => + syntaxError("illegal start of definition", true); + List() + } + + /** ClassDef ::= ClassSig {`,' ClassSig} [`:' SimpleType] ClassTemplate + * ClassSig ::= Id [TypeParamClause] [ClassParamClause] + */ + def classDef(mods: int): List[Tree] = { + val lhs = new ListBuffer[Tuple4[Int, Name, List[AbsTypeDef], List[List[ValDef]]]]; + do { + lhs + Tuple4(in.skipToken(), + ident().toTypeName, + typeParamClauseOpt(true), + paramClauseOpt(true)) + } while (in.token == COMMA); + val thistpe = simpleTypedOpt(); + val template = classTemplate((mods & Flags.CASE) != 0); + + for (val Tuple4(pos, name, tparams, vparams) <- lhs.toList) yield + ClassDef(mods, name, tparams, vparams, thistpe.duplicate, + template.duplicate.asInstanceOf[Template]) setPos pos + } + + /** ObjectDef ::= Id { , Id } [`:' SimpleType] ClassTemplate + */ + def objectDef(mods: int): List[Tree] = { + val lhs = new ListBuffer[Pair[Int, Name]]; + do { + lhs + Pair(in.skipToken(), ident()); + } while (in.token == COMMA); + val thistpe = simpleTypedOpt(); + val template = classTemplate((mods & Flags.CASE)!= 0); + for (val Pair(pos, name) <- lhs.toList) yield + ModuleDef(mods, name, thistpe.duplicate, + template.duplicate.asInstanceOf[Template]) setPos pos + } + + /** ClassTemplate ::= [`extends' Constr] {`with' Constr} [TemplateBody] + */ + def classTemplate(isCaseClass:boolean): Template = { + atPos(in.pos) { + val parents = new ListBuffer[Tree]; + if (in.token == EXTENDS) { + in.nextToken(); + parents + constr() + } else { + parents + scalaAnyRefConstr() + } + parents + scalaObjectConstr(); + if (isCaseClass) parents + caseClassConstr(); + if (in.token == WITH) { + in.nextToken(); + template(parents) + } else if (in.token == LBRACE) { + Template(parents.toList, templateBody()) + } else { + if (!(in.token == SEMI || in.token == COMMA || in.token == RBRACE)) + syntaxError("`extends' or `{' expected", true); + Template(parents.toList, List()) + } + } + } + +////////// TEMPLATES //////////////////////////////////////////////////////////// + /** Template ::= Constr {`with' Constr} [TemplateBody] + */ + def template(): Template = template(new ListBuffer[Tree]); + + def template(parents: ListBuffer[Tree]): Template = { + parents + constr(); + while (in.token == WITH) { + in.nextToken(); + parents + constr() + } + val stats = if (in.token == LBRACE) templateBody() else List(); + Template(parents.toList, stats) + } + + /** Constr ::= StableId [TypeArgs] [`(' [Exprs] `)'] + */ + def constr(): Tree = { + var t: Tree = convertToTypeId(stableId()); + if (in.token == LBRACKET) + t = AppliedTypeTree(t, typeArgs()) setPos in.pos; + if (in.token == LPAREN) + t = Apply(t, argumentExprs()) setPos in.pos; + applyConstr(t) + } + + /** TemplateBody ::= `{' [TemplateStat {`;' TemplateStat}] `}' + */ + def templateBody(): List[Tree] = { + accept(LBRACE); + var body = templateStatSeq(); + if (body.length == 0) body = List(EmptyTree); + accept(RBRACE); + body + } + + /** Refinement ::= `{' [RefineStat {`;' RefineStat}] `}' + */ + def refinement(): List[Tree] = { + accept(LBRACE); + val body = refineStatSeq(); + accept(RBRACE); + body + } + +/////// STATSEQS ////////////////////////////////////////////////////////////// + + /** Packaging ::= package QualId `{' TopStatSeq `}' + */ + def packaging(): Tree = { + atPos(accept(PACKAGE)) { + val pkg = qualId(); + accept(LBRACE); + val stats = topStatSeq(); + accept(RBRACE); + makePackaging(pkg, stats) + } + } + + /** TopStatSeq ::= [TopStat {`;' TopStat}] + * TopStat ::= AttributeClauses Modifiers ClsDef + * | Packaging + * | Import + * | + */ + def topStatSeq(): List[Tree] = { + val stats = new ListBuffer[Tree]; + while (in.token != RBRACE && in.token != EOF) { + if (in.token == PACKAGE) { + stats + packaging() + } else if (in.token == IMPORT) { + stats ++ importClause() + } else if (in.token == CLASS || + in.token == CASECLASS || + in.token == TRAIT || + in.token == OBJECT || + in.token == CASEOBJECT || + in.token == LBRACKET || + isModifier) { + stats ++ + joinAttributes(attributeClauses(), joinComment(tmplDef(modifiers()))) + } else if (in.token != SEMI) { + syntaxError("illegal start of class or object definition", true); + } + if (in.token != RBRACE && in.token != EOF) accept(SEMI); + } + stats.toList + } + + /** TemplateStatSeq ::= TemplateStat {`;' TemplateStat} + * TemplateStat ::= Import + * | AttributeClauses Modifiers Def + * | AttributeClauses Modifiers Dcl + * | Expr + * | + */ + def templateStatSeq(): List[Tree] = { + val stats = new ListBuffer[Tree]; + while (in.token != RBRACE && in.token != EOF) { + if (in.token == IMPORT) { + stats ++ importClause() + } else if (isExprIntro) { + stats + expr() + } else if (isDefIntro || isModifier || in.token == LBRACKET) { + stats ++ + joinAttributes(attributeClauses(), joinComment(defOrDcl(modifiers()))) + } else if (in.token != SEMI) { + syntaxError("illegal start of definition", true); + } + if (in.token != RBRACE) accept(SEMI); + } + stats.toList + } + + /** AttributeClauses ::= {AttributeClause} + * AttributeClause ::= `[' Attribute {`,' Attribute} `]' + * Attribute ::= Constr + */ + def attributeClauses(): List[Tree] = { + var attrs = new ListBuffer[Tree]; + while (in.token == LBRACKET) { + in.nextToken(); + attrs + constr(); + while (in.token == COMMA) { + in.nextToken(); + attrs + constr() + } + accept(RBRACKET); + } + attrs.toList + } + + def joinAttributes(attrs: List[Tree], defs: List[Tree]): List[Tree] = + defs map (defn => + (attrs :\ defn) ((attr, tree) => Attributed(attr, tree) setPos attr.pos)); + + /** RefineStatSeq ::= RefineStat {`;' RefineStat} + * RefineStat ::= Dcl + * | type TypeDef + * | + */ + def refineStatSeq(): List[Tree] = { + val stats = new ListBuffer[Tree]; + while (in.token != RBRACE && in.token != EOF) { + if (isDclIntro) { + stats ++ joinComment(defOrDcl(0)) + } else if (in.token != SEMI) { + syntaxError("illegal start of declaration", true); + } + if (in.token != RBRACE) accept(SEMI); + } + stats.toList + } + + /** BlockStatSeq ::= { BlockStat `;' } [Expr] + * BlockStat ::= Import + * | Def + * | LocalModifiers TmplDef + * | Expr + * | + */ + def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] = { + while ((in.token != RBRACE) && (in.token != EOF) && (in.token != CASE)) { + if (in.token == IMPORT) { + stats ++ importClause(); + accept(SEMI); + } else if (isExprIntro) { + stats + expr(false, true); + if (in.token != RBRACE && in.token != CASE) accept(SEMI); + } else if (isDefIntro) { + stats ++ defOrDcl(0); + accept(SEMI); + if (in.token == RBRACE || in.token == CASE) { + stats + Literal(()).setPos(in.pos) + } + } else if (isLocalModifier) { + stats ++ tmplDef(localClassModifiers()); + accept(SEMI); + if (in.token == RBRACE || in.token == CASE) { + stats + Literal(()).setPos(in.pos) + } + } else if (in.token == SEMI) { + in.nextToken(); + } else { + syntaxError("illegal start of statement", true); + } + } + stats.toList + } + + /** CompilationUnit ::= [ package QualId ( `;' | `{' TopStatSeq `}' ) ] TopStatSeq . + */ + def compilationUnit(): List[Tree] = { + if (in.token == PACKAGE) { + val pos = in.skipToken(); + val pkg = qualId(); + if (in.token == SEMI) { + in.nextToken(); + List(makePackaging(pkg, topStatSeq()) setPos pos); + } else { + val stats = new ListBuffer[Tree]; + accept(LBRACE); + stats + atPos(pos) { makePackaging(pkg, topStatSeq()) } + accept(RBRACE); + stats ++ topStatSeq(); + stats.toList + } + } else { + topStatSeq() + } + } + } +} + +// LocalWords: SOcos diff --git a/sources/scala/tools/nsc/ast/parser/TokenData.scala b/sources/scala/tools/nsc/ast/parser/TokenData.scala new file mode 100644 index 0000000000..7a74dfb092 --- /dev/null +++ b/sources/scala/tools/nsc/ast/parser/TokenData.scala @@ -0,0 +1,2 @@ +package scala.tools.nsc.ast.parser; + diff --git a/sources/scala/tools/nsc/ast/parser/Tokens.scala b/sources/scala/tools/nsc/ast/parser/Tokens.scala new file mode 100644 index 0000000000..8f3247acd3 --- /dev/null +++ b/sources/scala/tools/nsc/ast/parser/Tokens.scala @@ -0,0 +1,85 @@ +package scala.tools.nsc.ast.parser; + +object Tokens { + + /** special tokens */ + val EMPTY = -3; + val UNDEF = -2; + val ERROR = -1; + val EOF = 0; + + /** literals */ + val CHARLIT = 1; + val INTLIT = 2; + val LONGLIT = 3; + val FLOATLIT = 4; + val DOUBLELIT = 5; + val STRINGLIT = 6; + val SYMBOLLIT = 7; + + /** identifier */ + val IDENTIFIER = 10; + + /** keywords */ + val IF = 20; + val FOR = 21; + val ELSE = 22; + val THIS = 23; + val NULL = 24; + val NEW = 25; + val WITH = 26; + val SUPER = 27; + val CASE = 28; + val CASECLASS = 29; + val CASEOBJECT = 30; + val VAL = 31; + val ABSTRACT = 32; + val FINAL = 33; + val PRIVATE = 34; + val PROTECTED = 35; + val OVERRIDE = 36; + val VAR = 37; + val DEF = 38; + val TYPE = 39; + val EXTENDS = 40; + val TRUE = 41; + val FALSE = 42; + val OBJECT = 43; + val CLASS = 44; + + val IMPORT = 46; + val PACKAGE = 47; + val YIELD = 48; + val DO = 49; + val TRAIT = 50; + val SEALED = 51; + val THROW = 52; + val TRY = 53; + val CATCH = 54; + val FINALLY = 55; + val WHILE = 56; + val RETURN = 57; + + /** special symbols */ + val COMMA = 61; + val SEMI = 62; + val DOT = 63; + val USCORE = 64; + val COLON = 65; + val EQUALS = 66; + val LARROW = 67; + val ARROW = 68; + val SUBTYPE = 69; + val SUPERTYPE = 70; + val HASH = 71; + val AT = 72; + val VIEWBOUND = 73; + + /** parenthesis */ + val LPAREN = 90; + val RPAREN = 91; + val LBRACKET = 92; + val RBRACKET = 93; + val LBRACE = 94; + val RBRACE = 95; +} diff --git a/sources/scala/tools/nsc/build b/sources/scala/tools/nsc/build new file mode 100755 index 0000000000..76113a10f6 --- /dev/null +++ b/sources/scala/tools/nsc/build @@ -0,0 +1 @@ +/home/linuxsoft/apps/scala/bin/scalac -d /tmp/classes *.scala ast/*.scala ast/parser/*.scala symtab/*.scala symtab/classfile/*.scala util/*.scala $*
\ No newline at end of file diff --git a/sources/scala/tools/nsc/build.bat b/sources/scala/tools/nsc/build.bat new file mode 100755 index 0000000000..810d74d61e --- /dev/null +++ b/sources/scala/tools/nsc/build.bat @@ -0,0 +1 @@ +scalac -d c:\classes *.scala ast/*.scala ast/parser/*.scala symtab/*.scala symtab/classfile/*.scala util/*.scala %1 %2 %3 %4 %5
\ No newline at end of file diff --git a/sources/scala/tools/nsc/grepnsc b/sources/scala/tools/nsc/grepnsc new file mode 100644 index 0000000000..df9006b7dd --- /dev/null +++ b/sources/scala/tools/nsc/grepnsc @@ -0,0 +1 @@ +grep $1 *.scala ast/*.scala ast/parser/*.scala symtab/*.scala symtab/classfile/*.scala util/*.scala
\ No newline at end of file diff --git a/sources/scala/tools/nsc/scalac b/sources/scala/tools/nsc/scalac new file mode 100755 index 0000000000..e69de29bb2 --- /dev/null +++ b/sources/scala/tools/nsc/scalac diff --git a/sources/scala/tools/nsc/symtab/Definitions.scala b/sources/scala/tools/nsc/symtab/Definitions.scala new file mode 100755 index 0000000000..205ada1bf4 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/Definitions.scala @@ -0,0 +1,231 @@ +package scala.tools.nsc.symtab; + +import scala.tools.util.Position; +import Flags._; + +abstract class Definitions: SymbolTable { + object definitions { + + // root packages and classes + var RootClass: Symbol = _; + + var JavaPackage: Symbol = _; + var JavaLangPackage: Symbol = _; + var ScalaPackage: Symbol = _; + var ScalaPackageClass: Symbol = _; + + var AnyClass: Symbol = _; + var AnyValClass: Symbol = _; + var ObjectClass: Symbol = _; + + var AnyRefClass: Symbol = _; + + var AllRefClass: Symbol = _; + var AllClass: Symbol = _; + + var StringClass: Symbol = _; + var ThrowableClass: Symbol = _; + + // the scala value classes + var UnitClass: Symbol = _; + var BooleanClass: Symbol = _; + var ByteClass: Symbol = _; + var ShortClass: Symbol = _; + var CharClass: Symbol = _; + var IntClass: Symbol = _; + var LongClass: Symbol = _; + var FloatClass: Symbol = _; + var DoubleClass: Symbol = _; + + // the scala reference classes + var ScalaObjectClass: Symbol = _; + var AttributeClass: Symbol = _; + var RefClass: Symbol = _; + var PartialFunctionClass: Symbol = _; + var IterableClass: Symbol = _; + var IteratorClass: Symbol = _; + var SeqClass: Symbol = _; + var ListClass: Symbol = _; + var ArrayClass: Symbol = _; + var TypeClass: Symbol = _; + var PredefModule: Symbol = _; + var ConsoleModule: Symbol = _; + var MatchErrorModule: Symbol = _; + var NilModule: Symbol = _; + var ConsClass: Symbol = _; + var RepeatedParamClass: Symbol = _; + + def TupleClass(i: int): Symbol = getClass("scala.Tuple" + i); + def FunctionClass(i: int): Symbol = getClass("scala.Function" + i); + + // members of class scala.Any + var Any_== : Symbol = _; + var Any_!= : Symbol = _; + var Any_equals : Symbol = _; + var Any_hashCode : Symbol = _; + var Any_toString : Symbol = _; + var Any_isInstanceOf: Symbol = _; + var Any_asInstanceOf: Symbol = _; + var Any_match : Symbol = _; + + // members of class java.lang.{Object, String} + var Object_eq : Symbol = _; + var Object_synchronized: Symbol = _; + var String_+ : Symbol = _; + + // pattern wildcard + var PatternWildcard: Symbol = _; + + def getModule(fullname: Name): Symbol = + getModuleOrClass(fullname, true); + def getClass(fullname: Name): Symbol = + getModuleOrClass(fullname, false); + + private def getModuleOrClass(fullname: Name, module: boolean): Symbol = { + var sym = RootClass; + var i = 0; + var j = fullname.pos('.', i); + while (j < fullname.length) { + sym = sym.info.lookup(fullname.subName(i, j)); + i = j + 1; + j = fullname.pos('.', i) + } + val result = + if (module) + sym.info.lookup(fullname.subName(i, j)).withFlag(MODULE | PACKAGE) + else + sym.info.lookup(fullname.subName(i, j).toTypeName); + if (result == NoSymbol) + throw new FatalError((if (module) "object " else "class ") + fullname + " not found."); + result + } + + private def newClass(owner: Symbol, name: Name, parents: List[Type]): Symbol = { + val clazz = owner.newClass(Position.NOPOS, name.toTypeName); + clazz.setInfo(ClassInfoType(parents, new Scope(), clazz)); + owner.info.members.enter(clazz); + clazz + } + + private def newAlias(owner: Symbol, name: Name, alias: Type): Symbol = { + val tpsym = owner.newAliasType(Position.NOPOS, name.toTypeName); + tpsym.setInfo(alias); + owner.info.members.enter(tpsym); + tpsym + } + + private def newMethod(owner: Symbol, name: Name): Symbol = { + val msym = owner.newMethod(Position.NOPOS, name); + owner.info.members.enter(msym); + msym + } + + private def newTypeParam(owner: Symbol, index: int): Symbol = + owner.newTypeParameter(Position.NOPOS, "T" + index) + .setInfo(TypeBounds(AllClass.tpe, AnyClass.tpe, AnyClass.tpe)); + + def init = { + RootClass = + NoSymbol.newClass(Position.NOPOS, nme.ROOT.toTypeName) + .setFlag(FINAL | PACKAGE | JAVA).setInfo(rootLoader); + + JavaPackage = getModule("java"); + JavaLangPackage = getModule("java.lang"); + ScalaPackage = getModule("scala"); + ScalaPackageClass = ScalaPackage.moduleClass; + + AnyClass = newClass(ScalaPackageClass, "Any", List()); + AnyValClass = getClass("scala.AnyVal"); + ObjectClass = getClass("java.lang.Object"); + + AnyRefClass = newAlias(ScalaPackageClass, "AnyRef", ObjectClass.tpe); + + AllRefClass = newClass(ScalaPackageClass, "AllRef", List(AnyRefClass.tpe)); + AllClass = newClass(ScalaPackageClass, "All", List(AnyClass.tpe)); + + StringClass = getClass("java.lang.String"); + ThrowableClass = getClass("java.lang.Throwable"); + + // the scala value classes + UnitClass = getClass("scala.Unit"); + BooleanClass = getClass("scala.Boolean"); + ByteClass = getClass("scala.Byte"); + ShortClass = getClass("scala.Short"); + CharClass = getClass("scala.Char"); + IntClass = getClass("scala.Int"); + LongClass = getClass("scala.Long"); + FloatClass = getClass("scala.Float"); + DoubleClass = getClass("scala.Double"); + + // the scala reference classes + ScalaObjectClass = getClass("scala.ScalaObject"); + AttributeClass = getClass("scala.Attribute"); + RefClass = getClass("scala.Ref"); + PartialFunctionClass = getClass("scala.PartialFunction"); + IterableClass = getClass("scala.Iterable"); + IteratorClass = getClass("scala.Iterator"); + SeqClass = getClass("scala.Seq"); + ListClass = getClass("scala.List"); + ArrayClass = getClass("scala.Array"); + TypeClass = getClass("scala.Type"); + PredefModule = getModule("scala.Predef"); + ConsoleModule = getModule("scala.Console"); + MatchErrorModule = getModule("scala.MatchError"); + NilModule = getModule("scala.Nil"); + ConsClass = getClass("scala.$colon$colon"); + RepeatedParamClass = newClass(ScalaPackageClass, nme.REPEATED_PARAM_CLASS_NAME, List(SeqClass.tpe)); + + // members of class scala.Any + Any_== = newMethod(AnyClass, "==") + .setInfo(MethodType(List(AnyClass.tpe), BooleanClass.tpe)) + .setFlag(FINAL); + Any_!= = newMethod(AnyClass, "!=") + .setInfo(MethodType(List(AnyClass.tpe), BooleanClass.tpe)) + .setFlag(FINAL); + Any_equals = newMethod(AnyClass, "equals") + .setInfo(MethodType(List(AnyClass.tpe), BooleanClass.tpe)); + Any_hashCode = newMethod(AnyClass, "hashCode") + .setInfo(MethodType(List(), IntClass.tpe)); + Any_toString = newMethod(AnyClass, "toString") + .setInfo(MethodType(List(), StringClass.tpe)); + Any_isInstanceOf = newMethod(AnyClass, "isInstanceOf") + .setFlag(FINAL); + { val tparam = newTypeParam(Any_isInstanceOf, 0); + Any_isInstanceOf.setInfo(PolyType(List(tparam), BooleanClass.tpe)); + } + Any_asInstanceOf = newMethod(AnyClass, "asInstanceOf") + .setFlag(FINAL); + { val tparam = newTypeParam(Any_asInstanceOf, 0); + Any_asInstanceOf.setInfo(PolyType(List(tparam), tparam.typeConstructor)); + } + Any_match = newMethod(AnyClass, "match") + .setFlag(FINAL); + { val tparam0 = newTypeParam(Any_match, 0); + val tparam1 = newTypeParam(Any_match, 1); + Any_match.setInfo( + PolyType( + List(tparam0, tparam1), + MethodType(List(tparam0.typeConstructor), tparam1.typeConstructor))); + } + + // members of class java.lang.{Object, String} + Object_eq = newMethod(ObjectClass, "eq") + .setInfo(MethodType(List(AnyRefClass.tpe), BooleanClass.tpe)) + .setFlag(FINAL); + Object_synchronized = newMethod(ObjectClass, "synchronized") + .setFlag(FINAL); + { val tparam = newTypeParam(Object_synchronized, 0); + Object_synchronized.setInfo( + PolyType( + List(tparam), + MethodType(List(tparam.typeConstructor), tparam.typeConstructor))); + } + String_+ = newMethod(StringClass, "+") + .setInfo(MethodType(List(AnyClass.tpe), StringClass.tpe)) + .setFlag(FINAL); + + // pattern wildcard + PatternWildcard = NoSymbol.newValue(Position.NOPOS, "_").setInfo(AllClass.tpe) + } + } +} diff --git a/sources/scala/tools/nsc/symtab/Flags.scala b/sources/scala/tools/nsc/symtab/Flags.scala new file mode 100644 index 0000000000..754ecaa26a --- /dev/null +++ b/sources/scala/tools/nsc/symtab/Flags.scala @@ -0,0 +1,82 @@ +package scala.tools.nsc.symtab; + +object Flags { + + // modifiers + val DEFERRED = 0x00000001; // was `abstract' for members + val FINAL = 0x00000002; + val PRIVATE = 0x00000004; + val PROTECTED = 0x00000008; + + val SEALED = 0x00000010; + val OVERRIDE = 0x00000020; + val CASE = 0x00000040; + val ABSTRACT = 0x00000080; // abstract class, or used in conjunction + // with abstract override. + // Note difference to DEFERRED! + + val METHOD = 0x00000100; // a def parameter + val TRAIT = 0x00000200; // a trait + val JAVA = 0x00000400; // symbol was defined by a Java class + val MODULE = 0x00000800; // symbol is module or class implementing a module + + val MUTABLE = 0x00001000; // symbol is a mutable variable. + val PARAM = 0x00002000; // symbol is a (value or type) parameter to a method + val PACKAGE = 0x00004000; // symbol is a java package + val DEPRECATED = 0x00008000; // symbol is deprecated. + + val COVARIANT = 0x00010000; // symbol is a covariant type variable + val CONTRAVARIANT = 0x00020000; // symbol is a contravariant type variable + val SYNTHETIC = 0x00040000; // symbol is compiler-generated + val STABLE = 0x00080000; // functions that are assumed to be stable + // (typically, access methods for valdefs) + val INITIALIZED = 0x00100000; // symbol's definition is complete + val LOCKED = 0x00200000; // temporary flag to catch cyclic dependencies + val ACCESSED = 0x00400000; // symbol was accessed at least once + val SELECTOR = 0x00800000; // symbol was used as selector in Select + + val CAPTURED = 0x01000000; // variables is accessed from nested function. Set by LambdaLift + val ACCESSOR = 0x02000000; // function is an access function for a value or variable + val ACCESS_METHOD = 0x04000000; // function is an access function for a method in some + // outer class; set by ExplicitOuter + val PARAMACCESSOR = 0x08000000; // for methods: is an access method for a val parameter + // for parameters: is a val parameter + + val LABEL = 0x10000000; // symbol is a label. Set by TailCall + val BRIDGE = 0x20000000; // function is a bridge method. Set by Erasure + val IS_ERROR = 0x40000000; // symbol is an error symbol + + val TRANS_FLAG = 0x80000000; // transient flag guaranteed to be reset after each phase. + val LIFTED = TRANS_FLAG; // transient flag for lambdalift + val INCONSTRUCTOR = TRANS_FLAG; // transient flag for analyzer + + // masks + val SOURCEFLAGS = 0x00037777; // these modifiers can be set in source programs. + val ACCESSFLAGS = PRIVATE | PROTECTED; + val VARIANCES = COVARIANT | CONTRAVARIANT; + val CONSTRFLAGS = CASE | JAVA; + + /** Flags already set by object creation and never set afterwards */ + val CREATIONFLAGS = ACCESSFLAGS | METHOD | MODULE | MUTABLE | PARAM | PACKAGE | + COVARIANT | CONTRAVARIANT | SYNTHETIC | STABLE | ACCESSOR | PARAMACCESSOR | IS_ERROR; + + /** Module flags inherited by their module-class */ + val MODULE2CLASSFLAGS = ACCESSFLAGS | PACKAGE; + + def flagsToString(flags: long): String = + List.range(0, 63) + .map(i => flagToString(flags & (1L << i))) + .filter("" !=).mkString("", " ", ""); + + private def flagToString(flag: long): String = flag.asInstanceOf[int] match { + case PRIVATE => "private" + case PROTECTED => "protected" + case ABSTRACT => "abstract" + case FINAL => "final" + case SEALED => "sealed" + case TRAIT => "trait" + case OVERRIDE => "override" + case CASE => "case" + case _ => "" + } +} diff --git a/sources/scala/tools/nsc/symtab/InfoTransformers.scala b/sources/scala/tools/nsc/symtab/InfoTransformers.scala new file mode 100644 index 0000000000..fb32abc7b7 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/InfoTransformers.scala @@ -0,0 +1,39 @@ +package scala.tools.nsc.symtab; + +abstract class InfoTransformers: SymbolTable { + + abstract class InfoTransformer { + private var prev: InfoTransformer = this; + private var next: InfoTransformer = this; + + val phase: Phase; + def transform(sym: Symbol, tpe: Type): Type; + + def insert(that: InfoTransformer): unit = { + assert(this.phase.id != that.phase.id); + if (that.phase.id < this.phase.id) { + prev insert that + } else if (next.phase.id <= that.phase.id && next.phase != NoPhase) { + next insert that + } else { + that.next = next; + that.prev = this; + next.prev = that; + this.next = that + } + } + + def nextFrom(from: Phase): InfoTransformer = + if (from.id == this.phase.id) this + else if (from.id < this.phase.id) + if (prev.phase.id < from.id) this + else prev.nextFrom(from); + else if (next.phase == NoPhase) next + else next.nextFrom(from); + } +} + + + + + diff --git a/sources/scala/tools/nsc/symtab/Names.scala b/sources/scala/tools/nsc/symtab/Names.scala new file mode 100755 index 0000000000..0c5226c1c3 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/Names.scala @@ -0,0 +1,272 @@ +package scala.tools.nsc.symtab; + +import scala.tools.nsc.util.NameTransformer; + +class Names { + +// Operations ------------------------------------------------------------- + + private val HASH_SIZE = 0x8000; + private val HASH_MASK = 0x7FFF; + private val NAME_SIZE = 0x20000; + + /** memory to store all names sequentially + */ + var chrs: Array[char] = new Array[char](NAME_SIZE); + private var nc = 0; + + /** hashtable for finding term names quickly + */ + private val termHashtable = new Array[Name](HASH_SIZE); + + /** hashtable for finding type names quickly + */ + private val typeHashtable = new Array[Name](HASH_SIZE); + + /** the hashcode of a name + */ + private def hashValue(cs: Array[char], offset: int, len: int): int = + if (len > 0) + len * (41 * 41 * 41) + + cs(offset) * (41 * 41) + + cs(offset + len - 1) * 41 + + cs(offset + (len >> 1)); + else 0; + + /** is (the ascii representation of) name at given index equal to + * cs[offset..offset+len-1]? + */ + private def equals(index: int, cs: Array[char], offset: int, len: int): boolean = { + var i = 0; + while ((i < len) && (chrs(index + i) == cs(offset + i))) + i = i + 1; + i == len + } + + /** enter characters into chrs array + */ + private def enterChars(cs: Array[char], offset: int, len: int): unit = { + var i = 0; + while (i < len) { + if (nc == chrs.length) { + val newchrs = new Array[char](chrs.length * 2); + System.arraycopy(chrs, 0, newchrs, 0, chrs.length); + chrs = newchrs; + } + chrs(nc + i) = cs(offset + i); + i = i + 1 + } + if (len == 0) nc = nc + 1 + else nc = nc + len + } + + /** create a term name from the characters in cs[offset..offset+len-1]. + */ + def newTermName(cs: Array[char], offset: int, len: int): Name = { + val h = hashValue(cs, offset, len) & HASH_MASK; + var n = termHashtable(h); + while ((n != null) && (n.length != len || !equals(n.start, cs, offset, len))) + n = n.next; + if (n == null) { + n = new TermName(nc, len, h); + enterChars(cs, offset, len); + } + n + } + + /** create a term name from string + */ + def newTermName(s: String): Name = + newTermName(s.toCharArray(), 0, s.length()); + + /** create a type name from the characters in cs[offset..offset+len-1]. + */ + def newTypeName(cs: Array[char], offset: int, len: int): Name = { + val h = hashValue(cs, offset, len) & HASH_MASK; + var n = typeHashtable(h); + while ((n != null) && (n.length != len || !equals(n.start, cs, offset, len))) + n = n.next; + if (n == null) { + n = new TypeName(nc, len, h); + enterChars(cs, offset, len); + } + n + } + + /** create a type name from string + */ + def newTypeName(s: String): Name = + newTypeName(s.toCharArray(), 0, s.length()); + + def nameChars: Array[char] = chrs; + + def view(s: String): Name = newTermName(s); + +// Classes ---------------------------------------------------------------------- + + /** The name class */ + abstract class Name(index: int, len: int) extends Function1[int, char] { + + /** Index into name table */ + def start: int = index; + + /** next name in the same hash bucket + */ + var next: Name = null; + + /** return the length of this name + */ + final def length: int = len; + + def isTermName: boolean; + def isTypeName: boolean; + def toTermName: Name; + def toTypeName: Name; + + + /** copy bytes of this name to buffer cs, starting at offset + */ + final def copyChars(cs: Array[char], offset: int) = + System.arraycopy(chrs, index, cs, offset, len); + + /** return the ascii representation of this name + */ + final def toChars = { + val cs = new Array[char](len); + copyChars(cs, 0); + cs + } + + /** return the string representation of this name + */ + final override def toString(): String = new String(chrs, index, len); + + /** return the hash value of this name + */ + final override def hashCode(): int = index; + + /** return the i'th char of this name + */ + final def apply(i: int): char = chrs(index + i); + + /** return the index of first occurrence of char c in this name, length if not found + */ + final def pos(c: char): int = pos(c, 0); + + /** return the index of first occurrence of char c in this name from `start', + * length if not found + */ + final def pos(c: char, start: int): int = { + var i = start; + while (i < len && chrs(index + i) != c) i = i + 1; + i + } + + /** return the index of last occurrence of char c in this name, -1 if not found. + */ + final def lastPos(c: char): int = lastPos(c, len - 1); + + /** return the index of last occurrence of char c in this name from `start', + * -1 if not found + */ + final def lastPos(c: char, start: int): int = { + var i = start; + while (i >= 0 && chrs(index + i) != c) i = i - 1; + i + } + + /** does this name start with prefix? + */ + final def startsWith(prefix: Name): boolean = startsWith(prefix, 0); + + /** does this name start with prefix at given start index? + */ + final def startsWith(prefix: Name, start: int): boolean = { + var i = 0; + while (i < prefix.length && start + i < len && chrs(index + start + i) == chrs(prefix.start + i)) + i = i + 1; + i == prefix.length + } + + /** does this name end with suffix? + */ + final def endsWith(suffix: Name): boolean = endsWith(suffix, len); + + /** does this name end with suffix just before given end index? + */ + final def endsWith(suffix: Name, end: int): boolean = { + var i = 1; + while (i <= suffix.length && i <= end && chrs(index + end - i) == chrs(suffix.start + suffix.length - i)) + i = i - 1; + i == suffix.length + } + + /** the subname with characters from start to end-1 + */ + def subName(from: int, to: int): Name; + + /** replace all occurrences of `from' by `to' in name. + * result is always a term name. + */ + def replace(from: char, to: char): Name = { + val cs = new Array[char](len); + var i = 0; + while (i < len) { + val ch = this(i); + cs(i) = if (ch == from) to else ch; + i = i + 1 + } + newTermName(cs, 0, len) + } + + /** Replace operator symbols by corresponding "$op_name" */ + def encode: Name = { + val str = toString(); + val res = NameTransformer.encode(str); + if (res == str) this + else if (isTypeName) newTypeName(str) + else newTermName(str) + } + + /** Replace $op_name by corresponding operator symbol */ + def decode: String = NameTransformer.decode(toString()) + } + + private class TermName(index: int, len: int, hash: int) extends Name(index, len) { + next = termHashtable(hash); + termHashtable(hash) = this; + def isTermName: boolean = true; + def isTypeName: boolean = false; + def toTermName: Name = this; + def toTypeName = { + val h = hashValue(chrs, index, len) & HASH_MASK; + var n = typeHashtable(h); + while (n != null && n.start != index) + n = n.next; + if (n == null) + n = new TypeName(index, len, h); + n + } + def subName(from: int, to: int): Name = + newTermName(chrs, start + from, to - from); + } + + private class TypeName(index: int, len: int, hash: int) extends Name(index, len) { + next = typeHashtable(hash); + typeHashtable(hash) = this; + def isTermName: boolean = false; + def isTypeName: boolean = true; + def toTermName: Name = { + val h = hashValue(chrs, index, len) & HASH_MASK; + var n = termHashtable(h); + while (n != null && n.start != index) + n = n.next; + if (n == null) + n = new TermName(index, len, h); + n + } + def toTypeName: Name = this; + def subName(from: int, to: int): Name = + newTypeName(chrs, start + from, to - from); + } +} diff --git a/sources/scala/tools/nsc/symtab/Scopes.scala b/sources/scala/tools/nsc/symtab/Scopes.scala new file mode 100755 index 0000000000..d22d82769f --- /dev/null +++ b/sources/scala/tools/nsc/symtab/Scopes.scala @@ -0,0 +1,232 @@ +package scala.tools.nsc.symtab; + +abstract class Scopes: SymbolTable { + + abstract class ScopeEntry(val sym: Symbol, val owner: Scope) { + + /** the next entry in the hash bucket + */ + var tail: ScopeEntry = _; + + /** the next entry in this scope + */ + var next: ScopeEntry = null; + + override def hashCode(): int = sym.name.start; + override def toString(): String = sym.toString(); + } + + def newScopeEntry(sym: Symbol, owner: Scope) = new ScopeEntry(sym, owner) { + next = owner.elems; + owner.elems = this; + } + + object NoScopeEntry extends ScopeEntry(NoSymbol, null); + + class Scope(initElems: ScopeEntry) { + + var elems: ScopeEntry = initElems; + + /** the hash table + */ + private var hashtable: Array[ScopeEntry] = null; + + /** a cache for all elements, to be used by symbol iterator. + */ + private var elemsCache: List[Symbol] = null; + + /** size and mask of hash tables + * todo: make hashtables grow? + */ + private val HASHSIZE = 0x80; + private val HASHMASK = 0x7f; + + /** the threshold number of entries from which a hashtable is constructed. + */ + private val MIN_HASH = 8; + + if (size >= MIN_HASH) createHash; + + def this() = this(null: ScopeEntry); + + def this(base: Scope) = { + this(base.elems); + if (base.hashtable != null) { + this.hashtable = new Array[ScopeEntry](HASHSIZE); + System.arraycopy(base.hashtable, 0, this.hashtable, 0, HASHSIZE); + } + } + + def this(members: List[Symbol]) = { + this(); + members foreach enter + } + + /** Returns a new scope with the same content as this one. */ + def cloneScope: Scope = { + val clone = new Scope(); + this.toList foreach clone.enter; + clone + } + + /** is the scope empty? */ + def isEmpty: boolean = elems == null; + + /** the number of entries in this scope */ + def size: int = { + var s = 0; + var e = elems; + while (e != null) { + s = s + 1; + e = e.next + } + s + } + + /** enter a scope entry + */ + def enter(e: ScopeEntry): unit = { + elems = e; + elemsCache = null; + if (hashtable != null) { + val i = e.sym.name.start & HASHMASK; + elems.tail = hashtable(i); + hashtable(i) = elems; + } else if (size >= MIN_HASH) { + createHash; + } + } + + /** enter a symbol + */ + def enter(sym: Symbol): unit = enter(newScopeEntry(sym, this)); + + private def createHash: unit = { + hashtable = new Array[ScopeEntry](HASHSIZE); + enterInHash(elems); + } + + private def enterInHash(e: ScopeEntry): unit = { + if (e != null) { + enterInHash(e.next); + val i = e.sym.name.start & HASHMASK; + e.tail = hashtable(i); + hashtable(i) = e; + } + } + + /** remove entry + */ + def unlink(e: ScopeEntry): unit = { + if (elems == e) { + elems = e.next; + } else { + var e1 = elems; + while (e1.next != e) e1 = e1.next; + e1.next = e.next; + } + if (hashtable != null) { + var e1 = hashtable(e.sym.name.start & HASHMASK); + if (e1 == e) { + hashtable(e.sym.name.start & HASHMASK) = e.tail; + } else { + while (e1.tail != e) e1 = e1.tail; + e1.tail = e.tail; + } + } + elemsCache = null + } + + /** remove symbol */ + def unlink(sym: Symbol): unit = + for (val e <- lookupAllEntries(sym.name)) + if (e.sym == sym) unlink(e); + + /** lookup a symbol + */ + def lookup(name: Name): Symbol = { + val e = lookupEntry(name); + if (e == null) NoSymbol else e.sym; + } + + /** lookup a symbol entry matching given name + */ + def lookupEntry(name: Name): ScopeEntry = { + var e: ScopeEntry = null; + if (hashtable != null) { + e = hashtable(name.start & HASHMASK); + while (e != null && e.sym.name != name) e = e.tail; + } else { + e = elems; + while (e != null && e.sym.name != name) e = e.next; + } + e + } + + /** Iterates through all symbol entries matching given name. + * Iteration is from last declared to first declared. + */ + def lookupAllEntries(name: Name) = new Iterator[ScopeEntry] { + var e: ScopeEntry = + if (hashtable != null) hashtable(name.start & HASHMASK) + else elems; + def hasNext: boolean = { + while (e != null && e.sym.name != name) + if (hashtable != null) e = e.tail else e = e.next; + e != null + } + def next: ScopeEntry = if (hasNext) { + val result = e; + if (hashtable != null) e = e.tail else e = e.next; + result + } else { + null + } + } + + /** Iterates through all symbols matching given name. + * Iteration is from last declared to first declared. + */ + def lookupAll(name: Name): Iterator[Symbol] = + lookupAllEntries(name) map (.sym); + + /** Return all symbols as a list in the order they were entered in this scope. + */ + def toList: List[Symbol] = { + if (elemsCache == null) { + elemsCache = Nil; + var e = elems; + while (e != null) { + elemsCache = e.sym :: elemsCache; + e = e.next + } + } + elemsCache + } + + override def toString(): String = + toList.map(.defString).mkString("{\n ", ";\n ", "\n}"); + } + + /** The empty scope (immutable). + */ + object EmptyScope extends Scope { + override def enter(e: ScopeEntry): unit = + throw new Error("EmptyScope.enter"); + } + + /** The error scope. + */ + class ErrorScope(owner: Symbol) extends Scope(null: ScopeEntry) { + override def lookupEntry(name: Name): ScopeEntry = { + val e = super.lookupEntry(name); + if (e != NoSymbol) e + else { + enter(if (name.isTermName) owner.newErrorValue(name) + else owner.newErrorClass(name)); + super.lookupEntry(name); + } + } + } +} + diff --git a/sources/scala/tools/nsc/symtab/StdNames.scala b/sources/scala/tools/nsc/symtab/StdNames.scala new file mode 100755 index 0000000000..267bec4142 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/StdNames.scala @@ -0,0 +1,193 @@ +package scala.tools.nsc.symtab; + +import scala.tools.nsc.util.NameTransformer; + +abstract class StdNames: SymbolTable { + + object nme { + + private val LOCAL_PREFIX_STRING = "local$"; + private val MIXIN_PREFIX_STRING = "mixin$"; + private val OUTER_PREFIX_STRING = "outer$"; + private val SUPER_PREFIX_STRING = "super$"; + private val ACCESS_PREFIX_STRING = "access$"; + private val TUPLE_FIELD_PREFIX_STRING = "_"; + private val TYPE_PREFIX_STRING = "type$"; + + val LOCAL_PREFIX = newTermName(LOCAL_PREFIX_STRING); + + def LOCAL(clazz: Symbol) = newTermName(LOCAL_PREFIX_STRING + clazz.name); + + def TUPLE_FIELD(index: int) = newTermName(TUPLE_FIELD_PREFIX_STRING + index); + + val ERROR = newTermName("<error>"); + val ERRORtype = newTypeName("<error>"); + + val NOSYMBOL = newTermName("<none>"); + val EMPTY = newTermName(""); + val WILDCARD = newTermName("_"); + val WILDCARD_STAR = newTermName("_*"); + val COMPOUND_NAME = newTermName("<ct>"); + val ANON_CLASS_NAME = newTermName("$anon"); + val REFINE_CLASS_NAME = newTermName("<refinement>"); + val ZERO = newTermName("<zero>"); + val STAR = newTermName("*"); + val ROOT = newTermName("<root>"); + val REPEATED_PARAM_CLASS_NAME = newTermName("<repeated>"); + + val CONSTRUCTOR = newTermName("<init>"); + val INITIALIZER = newTermName("<init>"); + val INLINED_INITIALIZER = newTermName("$init$"); + + val _EQ = encode("_="); + val MINUS = encode("-"); + val PLUS = encode("+"); + val TILDE = encode("~"); + val EQEQ = encode("=="); + val BANG = encode("!"); + val BANGEQ = encode("!="); + val BARBAR = encode("||"); + val AMPAMP = encode("&&"); + val COLONCOLON = encode("::"); + val PERCENT = encode("%"); + + val All = newTermName("All"); + val AllRef = newTermName("AllRef"); + val Any = newTermName("Any"); + val AnyVal = newTermName("AnyVal"); + val AnyRef = newTermName("AnyRef"); + val Array = newTermName("Array"); + val Byte = newTermName("Byte"); + val CaseClass = newTermName("CaseClass"); + val Catch = newTermName("Catch"); + val Char = newTermName("Char"); + val Boolean = newTermName("Boolean"); + val Do = newTermName("Do"); + val Double = newTermName("Double"); + val Element = newTermName("Element"); + val Finally = newTermName("Finally"); + val Float = newTermName("Float"); + val Function = newTermName("Function"); + val Int = newTermName("Int"); + val Labelled = newTermName("Labelled"); + val List = newTermName("List"); + val Long = newTermName("Long"); + val Nil = newTermName("Nil"); + val Object = newTermName("Object"); + val PartialFunction = newTermName("PartialFunction"); + val Predef = newTermName("Predef"); + val ScalaObject = newTermName("ScalaObject"); + val ScalaRunTime = newTermName("ScalaRunTime"); + val Seq = newTermName("Seq"); + val Short = newTermName("Short"); + val SourceFile = newTermName("SourceFile"); + val String = newTermName("String"); + val Symbol = newTermName("Symbol"); + val Synthetic = newTermName("Synthetic"); + + val Text = newTermName("Text"); + val Throwable = newTermName("Throwable"); + val Try = newTermName("Try"); + val Tuple = newTermName("Tuple"); + val Type = newTermName("Type"); + val Tuple2 = newTermName("Tuple2"); + val Unit = newTermName("Unit"); + val While = newTermName("While"); + val apply = newTermName("apply"); + val array = newTermName("array"); + val asInstanceOf = newTermName("asInstanceOf"); + val box = newTermName("box"); + val checkCastability = newTermName("checkCastability"); + val coerce = newTermName("coerce"); + val defaultValue = newTermName("defaultValue"); + val elem = newTermName("elem"); + val elements = newTermName("elements"); + val fail = newTermName("fail"); + val report = newTermName("report"); + val false_ = newTermName("false"); + val filter = newTermName("filter"); + val flatmap = newTermName("flatMap"); + val foreach = newTermName("foreach"); + val getClass_ = newTermName("getClass"); + val hasAsInstance = newTermName("hasAsInstance"); + val hashCode_ = newTermName("hashCode"); + val hasNext = newTermName("hasNext"); + val head = newTermName("head"); + val isInstanceOf = newTermName("isInstanceOf"); + val isDefinedAt = newTermName("isDefinedAt"); + val isEmpty = newTermName("isEmpty"); + val java = newTermName("java"); + val lang = newTermName("lang"); + val length = newTermName("length"); + val _match = newTermName("match"); + val map = newTermName("map"); + val n = newTermName("n"); + val nobinding = newTermName("nobinding"); + val next = newTermName("next"); + val newArray = newTermName("newArray"); + val null_ = newTermName("null"); + val predef = newTermName("predef"); + val print = newTermName("print"); + val runtime = newTermName("runtime"); + val scala = newTermName("scala"); + val xml = newTermName("xml"); + val synchronized_ = newTermName("synchronized"); + val caseArity = newTermName("caseArity"); + val caseElement = newTermName("caseElement"); + val eq = newTermName("eq"); + val equals = newTermName("equals"); + val tail = newTermName("tail"); + val toString_ = newTermName("toString"); + val that = newTermName("that"); + val that1 = newTermName("that1"); + val this_ = newTermName("this"); + val throw_ = newTermName("throw"); + val true_ = newTermName("true"); + val update = newTermName("update"); + val view_ = newTermName("view"); + val tag = newTermName("$tag"); + val finalize_ = newTermName("finalize"); + val wait = newTermName("wait"); + val notify_ = newTermName("notify"); + val notifyAll_ = newTermName("notifyAll"); + val GetType = newTermName("GetType"); + + val ZNOT = encode("!"); + val ZAND = encode("&&"); + val ZOR = encode("||"); + val NOT = encode("~"); + val ADD = encode("+"); + val SUB = encode("-"); + val MUL = encode("*"); + val DIV = encode("/"); + val MOD = encode("%"); + val EQ = encode("=="); + val NE = encode("!="); + val LT = encode("<"); + val LE = encode("<="); + val GT = encode(">"); + val GE = encode(">="); + val OR = encode("|"); + val XOR = encode("^"); + val AND = encode("&"); + val LSL = encode("<<"); + val LSR = encode(">>>"); + val ASR = encode(">>"); + + val SourceFileATTR = newTermName("SourceFile"); + val SyntheticATTR = newTermName("Synthetic"); + val BridgeATTR = newTermName("Bridge"); + val DeprecatedATTR = newTermName("Deprecated"); + val CodeATTR = newTermName("Code"); + val ExceptionsATTR = newTermName("Exceptions"); + val ConstantValueATTR = newTermName("ConstantValue"); + val LineNumberTableATTR = newTermName("LineNumberTable"); + val LocalVariableTableATTR = newTermName("LocalVariableTable"); + val InnerClassesATTR = newTermName("InnerClasses"); + val JacoMetaATTR = newTermName("JacoMeta"); + val ScalaSignatureATTR = newTermName("ScalaSignature"); + val JavaInterfaceATTR = newTermName("JacoInterface"); + } + + def encode(str: String): Name = newTermName(NameTransformer.encode(str)); +} diff --git a/sources/scala/tools/nsc/symtab/SymbolLoaders.scala b/sources/scala/tools/nsc/symtab/SymbolLoaders.scala new file mode 100755 index 0000000000..79cf3b6948 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -0,0 +1,142 @@ +package scala.tools.nsc.symtab; + +import java.io.IOException; +import scala.tools.util.{AbstractFile, Position} +import scala.tools.nsc.util.NameTransformer; +import scala.collection.mutable.HashMap; +import classfile.ClassfileParser; +import Flags._; + + +abstract class SymbolLoaders { + val global: Global; + import global._; + + /** A lazy type that completes itself by calling parameter doComplete. + * Any linked modules/classes or module classes are also initialized. + * @param doComplete The type completion procedure to be run. + * It takes symbol to compkete as parameter and returns + * name of file loaded for completion as a result. + * Can throw an IOException on error. + */ + class SymbolLoader(doComplete: Symbol => String) extends LazyType { + private var ok = false; + override def complete(root: Symbol): unit = { + try { + val start = System.currentTimeMillis(); + val currentphase = phase; + phase = analyzerPhase; + val source = doComplete(root); + phase = currentphase; + informTime("loaded " + source, start); + if (root.rawInfo != this) ok = true + else error(source + " does not define " + root) + } catch { + case ex: IOException => + if (settings.debug.value) ex.printStackTrace(); + val msg = ex.getMessage(); + error( + if (msg == null) "i/o error while loading " + root.name + else "error while loading " + root.name + ", " + msg); + } + initRoot(root); + if (!root.isPackageClass) + initRoot(if (root.isModule) root.linkedClass else root.linkedModule); + } + + private def initRoot(root: Symbol): unit = { + if (root.rawInfo == this) + root.setInfo(if (ok) NoType else ErrorType); + if (root.isModule) initRoot(root.moduleClass) + } + } + + /** Load contents of a package + */ + def packageLoader(directory: AbstractFile): SymbolLoader = + new SymbolLoader(root => { + System.out.println("loading " + root);//debug + assert(root.isPackageClass, root); + val members = new Scope(); + root.setInfo(new PackageClassInfoType(members, root)); + + def enterPackage(str: String, completer: SymbolLoader): unit = { + val pkg = root.newPackage(Position.NOPOS, newTermName(str)); + pkg.moduleClass.setInfo(completer); + pkg.setInfo(pkg.moduleClass.tpe); + members.enter(pkg) + } + + def enterClassAndModule(str: String, completer: SymbolLoader): unit = { + val name = newTermName(str); + val clazz = root.newClass(Position.NOPOS, name.toTypeName); + val module = root.newModule(Position.NOPOS, name); + clazz.setInfo(completer); + module.setInfo(completer); + module.moduleClass.setInfo(errorLoader); + members.enter(clazz); + members.enter(module); + assert(clazz.linkedModule == module); + assert(module.linkedClass == clazz); + } + + val sources = new HashMap[String, AbstractFile]; + val classes = new HashMap[String, AbstractFile]; + val packages = new HashMap[String, AbstractFile]; + val it = directory.list(); + while (it.hasNext()) { + val file = it.next().asInstanceOf[AbstractFile]; + val filename = file.getName(); + if (file.isDirectory()) { + if (filename != "META_INF") { + if (!packages.isDefinedAt(filename)) packages(filename) = file; + } + } else if (!root.isRoot && filename.endsWith(".class")) { + val name = filename.substring(0, filename.length() - 6); + if (!classes.isDefinedAt(name)) classes(name) = file; + } else if (!root.isRoot && filename.endsWith(".scala")) { + val name = filename.substring(0, filename.length() - 6); + if (!sources.isDefinedAt(name)) sources(name) = file; + } + } + for (val Pair(name, sfile) <- sources.elements) { + classes.get(name) match { + case Some(cfile) if (cfile.lastModified() > sfile.lastModified()) => {} + case _ => enterClassAndModule(name, sourcefileLoader(sfile)); + } + } + for (val Pair(name, cfile) <- classes.elements) { + sources.get(name) match { + case Some(sfile) if (sfile.lastModified() > cfile.lastModified()) => {} + case _ => enterClassAndModule(name, classfileLoader(cfile)); + } + } + for (val Pair(name, file) <- packages.elements) { + if (!sources.contains(name) && !classes.contains(name)) + enterPackage(name, packageLoader(file)); + } + + "directory path '" + directory + "'" + }); + + private object classfileParser extends ClassfileParser { + val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global; + } + + def classfileLoader(file: AbstractFile) = + new SymbolLoader(root => { + classfileParser.parse(file, root); + "class file '" + file + "'"; + }); + + def sourcefileLoader(file: AbstractFile) = + new SymbolLoader(root => { + global.compileLate(file, false); + "source file '" + file + "'"; + }); + + val errorLoader = + new SymbolLoader(root => { + throw new Error(" loading " + root + " without loading module first"); + }); +} diff --git a/sources/scala/tools/nsc/symtab/SymbolTable.scala b/sources/scala/tools/nsc/symtab/SymbolTable.scala new file mode 100755 index 0000000000..1a0ce88b67 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/SymbolTable.scala @@ -0,0 +1,35 @@ +package scala.tools.nsc.symtab; + +import util._; + +abstract class SymbolTable extends Names + with Symbols + with Types + with Scopes + with Definitions + with InfoTransformers + with StdNames { + def settings: Settings; + def rootLoader: LazyType; + + private var ph: Phase = NoPhase; + def phase: Phase = ph; + def phase_=(p: Phase): unit = { + //System.out.println("setting phase to " + p); + assert(p != null); + ph = p + } + + def atPhase[T](ph: Phase)(def op: T): T = { + val current = phase; + phase = ph; + val result = op; + phase = current; + result + } + + var infoTransformers = new InfoTransformer { + val phase = NoPhase; + def transform(sym: Symbol, tpe: Type): Type = tpe; + } +} diff --git a/sources/scala/tools/nsc/symtab/Symbols.scala b/sources/scala/tools/nsc/symtab/Symbols.scala new file mode 100755 index 0000000000..0f2017fe21 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/Symbols.scala @@ -0,0 +1,658 @@ +package scala.tools.nsc.symtab; + +import scala.tools.util.Position; +import Flags._; + +abstract class Symbols: SymbolTable { + import definitions._; + + private var ids = 0; + + val emptySymbolArray = new Array[Symbol](0); + + /** The class for all symbols */ + abstract class Symbol(initOwner: Symbol, initPos: int, initName: Name) { + + var owner = initOwner; + var name = initName; + var pos = initPos; + val id = { ids = ids + 1; ids } + private var rawflags: long = 0; + +// Creators ------------------------------------------------------------------- + + final def newValue(pos: int, name: Name) = + new TermSymbol(this, pos, name); + final def newVariable(pos: int, name: Name) = + newValue(pos, name).setFlag(MUTABLE); + final def newValueParameter(pos: int, name: Name) = + newValue(pos, name).setFlag(PARAM); + final def newLocalDummy(pos: int) = + newValue(pos, nme.LOCAL(owner)).setInfo(NoType); + final def newMethod(pos: int, name: Name) = + newValue(pos, name).setFlag(METHOD); + final def newLabel(pos: int, name: Name) = + newMethod(pos, name).setFlag(LABEL); + final def newConstructor(pos: int) = + newMethod(pos, nme.CONSTRUCTOR); + final def newModule(pos: int, name: Name, clazz: ClassSymbol) = + new ModuleSymbol(this, pos, name, clazz); + final def newModule(pos: int, name: Name) = + new ModuleSymbol(this, pos, name, null); + final def newPackage(pos: int, name: Name) = { + assert(isPackageClass); + val m = newModule(pos, name); + m.setFlag(JAVA | PACKAGE); + m.moduleClass.setFlag(JAVA | PACKAGE); + m + } + final def newThisSym(pos: int) = + newValue(pos, nme.this_).setFlag(SYNTHETIC); + final def newErrorValue(name: Name) = + newValue(pos, name).setFlag(SYNTHETIC | IS_ERROR).setInfo(ErrorType); + final def newAliasType(pos: int, name: Name) = + new TypeSymbol(this, pos, name); + final def newAbstractType(pos: int, name: Name) = + new TypeSymbol(this, pos, name).setFlag(DEFERRED); + final def newTypeParameter(pos: int, name: Name) = + newAbstractType(pos, name).setFlag(PARAM); + final def newClass(pos: int, name: Name) = + new ClassSymbol(this, pos, name); + final def newAnonymousClass(pos: int) = + newClass(pos, nme.ANON_CLASS_NAME.toTypeName); + final def newRefinementClass(pos: int) = + newClass(pos, nme.REFINE_CLASS_NAME.toTypeName); + final def newErrorClass(name: Name) = { + val clazz = newClass(pos, name).setFlag(SYNTHETIC | IS_ERROR); + clazz.setInfo(ClassInfoType(List(), new ErrorScope(this), clazz)); + clazz + } + + +// Tests ---------------------------------------------------------------------- + + def isTerm = false; //to be overridden + def isType = false; //to be overridden + def isClass = false; //to be overridden + + final def isValue = isTerm && !(isModule && ((rawflags & (PACKAGE | JAVA)) != 0)); + final def isVariable = isTerm && (rawflags & MUTABLE) != 0; + final def isValueParameter = isTerm && (rawflags & PARAM) != 0; + final def isLocalDummy = isTerm && (name startsWith nme.LOCAL_PREFIX); + final def isMethod = isTerm && (rawflags & METHOD) != 0; + final def isLabel = isTerm && (rawflags & LABEL) != 0; + final def isConstructor = isTerm && name == nme.CONSTRUCTOR; + final def isModule = isTerm && (rawflags & MODULE) != 0; + final def isPackage = isModule && (rawflags & PACKAGE) != 0; + final def isThisSym = isTerm && name == nme.this_; + final def isError = (rawflags & IS_ERROR) != 0; + final def isAliasType = isType && !isClass && (rawflags & DEFERRED) == 0; + final def isAbstractType = isType && !isClass && (rawflags & DEFERRED) != 0; + final def isTypeParameter = isType && (rawflags & PARAM) != 0; + final def isAnonymousClass = isClass && (name startsWith nme.ANON_CLASS_NAME); // startsWith necessary because name may grow when lifted + final def isRefinementClass = isClass && name == nme.REFINE_CLASS_NAME; // no lifting for refinement classes + final def isModuleClass = isClass && (rawflags & MODULE) != 0; + final def isPackageClass = isClass && (rawflags & PACKAGE) != 0; + final def isRoot = isPackageClass && name == nme.ROOT.toTypeName; + + /** Does this symbol denote a stable value? */ + final def isStable = + isTerm && (rawflags & MUTABLE) == 0 && + ((rawflags & METHOD) == 0 || (rawflags & STABLE) != 0); + + /** Does this symbol denote the primary constructor + * of its enclosing class? */ + final def isPrimaryConstructor = + isConstructor && owner.primaryConstructor == this; + + /** Is this symbol static (i.e. with no outer instance)? */ + final def isStatic: boolean = isRoot || owner.isStaticOwner; + + /** Does this symbol denote a class that defines static symbols? */ + final def isStaticOwner: boolean = isPackageClass || isStatic && isModuleClass; + + /** Is this symbol final?*/ + final def isFinal: boolean = hasFlag(FINAL | PRIVATE) || isLocal || owner.isModuleClass; + + /** Is this symbol locally defined? I.e. not a member of a class or module */ + final def isLocal: boolean = owner.isTerm; + + /** Is this class locally defined? + * A class is local, if + * - it is anonymous, or + * - its owner is a value + * - it is defined within a local class + */ + final def isLocalClass: boolean = + isClass && (isAnonymousClass || isRefinementClass || isLocal || + !owner.isPackageClass && owner.isLocalClass); + + /** Symbol was preloaded from package */ + final def isExternal: boolean = pos == Position.NOPOS; + + /** The variance of this symbol as an integer */ + final def variance: int = + if ((rawflags & COVARIANT) != 0) 1 + else if ((rawflags & CONTRAVARIANT) != 0) -1 + else 0; + +// Flags ---------------------------------------------------------------------------- + + final def flags = { + initialize; rawflags & phase.flagMask + } + final def setFlag(mask: long): Symbol = { + rawflags = rawflags | mask; this + } + final def resetFlag(mask: long): Symbol = { + rawflags = rawflags & ~mask; this + } + final def getFlag(mask: long): long = + (if ((mask & ~CREATIONFLAGS) == 0) rawflags else flags) & mask; + final def hasFlag(mask: long): boolean = + ((if ((mask & ~CREATIONFLAGS) == 0) rawflags else flags) & mask) != 0; + final def resetFlags = + rawflags = rawflags & SOURCEFLAGS; + +// Info and Type ------------------------------------------------------------------- + + private var infos: TypeHistory = null; + private var limit: Phase = NoPhase; + + /** Get type. The type of a symbol is: + * for a type symbol, the type corresponding to the symbol itself + * for a term symbol, its usual type + */ + def tpe: Type = info; + + /** Get type info associated with symbol at current phase, after + * ensuring that symbol is initialized (i.e. type is completed). + */ + final def info: Type = { + var cnt = 0; + while ((rawflags & INITIALIZED) == 0) { + assert(infos != null, "infos null for " + this.name);//debug + val tp = infos.info; + if ((rawflags & LOCKED) != 0) { + setInfo(ErrorType); + throw new CyclicReference(this, tp); + } + rawflags = rawflags | LOCKED; + val current = phase; + phase = infos.start; + //System.out.println("completing " + this);//DEBUG + tp.complete(this); + phase = current; + rawflags = rawflags & ~LOCKED; + cnt = cnt + 1; + // allow for two completions: + // one: sourceCompleter to LazyType, two: LazyType to completed type + if (cnt == 2) throw new Error("no progress in completing " + this + ":" + tp); + } + rawInfo + } + + /** Set initial info. */ + def setInfo(info: Type): Symbol = { + infos = new TypeHistory(phase, info, null); + limit = phase; + assert(info != null, "setInfo(null) for " + name + " at phase " + phase);//debug + rawflags = if (info.isComplete) rawflags | INITIALIZED + else rawflags & ~INITIALIZED; + if (info.isInstanceOf[MethodType] || info.isInstanceOf[PolyType]) + assert(isClass || (rawflags & METHOD) != 0); + this + } + + /** Set new info valid from start of next phase. */ + final def updateInfo(info: Type): Symbol = { + val current = phase; + phase = phase.next; + assert(infos.start.id <= phase.id); + if (infos.start == phase) infos = infos.prev; + infos = new TypeHistory(phase, info, infos); + phase = current; + this + } + + /** Return info without checking for initialization or completing */ + final def rawInfo: Type = { + if (limit.id < phase.id) { + if ((rawflags & INITIALIZED) != 0) { + val current = phase; + var itr = infoTransformers.nextFrom(limit); + infoTransformers = itr; // caching optimization + while (itr.phase != NoPhase && itr.phase.id < current.id) { + phase = itr.phase; + val info1 = itr.transform(this, infos.info); + if (!(info1 eq infos.info)) + infos = new TypeHistory(phase.next, info1, infos); + itr = itr.nextFrom(phase.next) + } + phase = current; + limit = current; + } + assert(infos != null, "info = null at " + this.name + " " + limit + " " + phase);//debug + infos.info + } else { + var infos = this.infos; + while (phase.id < infos.start.id && infos.prev != null) infos = infos.prev; + infos.info + } + } + + /** Initialize the symbol */ + final def initialize: Symbol = { + if ((rawflags & INITIALIZED) == 0) info; + this + } + + /** Was symbol's type updated during given phase? */ + final def isUpdatedAt(phase: Phase): boolean = { + var infos = this.infos; + while (infos != null && infos.start != phase.next) infos = infos.prev; + infos != null + } + + /** The type constructor of a symbol is: + * For a type symbol, the type corresponding to the symbol itself, + * excluding parameters. + * Not applicable for term symbols. + */ + def typeConstructor: Type = throw new Error("typeConstructor inapplicable for " + this); + + /** The type parameters of this symbol */ + def typeParams: List[Symbol] = rawInfo.typeParams; + +// Comparisons ---------------------------------------------------------------- + + /** A total ordering between symbols that refines the class + * inheritance graph (i.e. subclass.isLess(superclass) always holds). + * the ordering is given by: (isType, -|closure| for type symbols, id) + */ + final def isLess(that: Symbol): boolean = + if (this.isType) + that.isType && + {val diff = this.info.closure.length - that.info.closure.length; + diff > 0 || diff == 0 && this.id < that.id} + else + that.isType || this.id < that.id; + + /** A partial ordering between symbols. + * (this isNestedIn that) holds iff this symbol is defined within + * a class or method defining that symbol + */ + final def isNestedIn(that: Symbol): boolean = + owner == that || owner != NoSymbol && (owner isNestedIn that); + + /** Is this class symbol a subclass of that symbol? */ + final def isSubClass(that: Symbol): boolean = + this == that || this.isError || that.isError || + info.closurePos(that) >= 0 || + this == AllClass || + this == AllRefClass && + (that == AnyClass || + that != AllClass && (that isSubClass AnyRefClass)); + +// Overloaded Alternatives --------------------------------------------------------- + + /** All overloaded alternatives of this symbol */ + def alternatives: Iterator[Symbol] = + Iterator.fromValues(this); + + private def findUnique(alts: Iterator[Symbol], p: Symbol => boolean): Symbol = { + if (alts.hasNext) { + val alt = alts.next; + if (p(alt)) { + while (alts.hasNext) assert(!p(alts.next)); + alt + } else findUnique(alts, p) + } else NoSymbol + } + + /** The unique alternative whose type at given prefix `pre' matches `tp' + * or NoSymbol, if no such alternatives exist. + */ + final def matching(pre: Type, tp: Type): Symbol = + findUnique(alternatives, alt => pre.memberType(alt).matches(tp)); + + final def withFlag(mask: long): Symbol = + findUnique(alternatives, .hasFlag(mask)); + + /** Reset symbol to initial state + */ + def reset(completer: Type): unit = { + resetFlags; + pos = Position.NOPOS; + infos = null; + setInfo(completer) + } + +// Cloneing ------------------------------------------------------------------- + + /** A clone of this symbol */ + final def cloneSymbol: Symbol = + cloneSymbol(owner); + + /** A clone of this symbol, but with given owner */ + final def cloneSymbol(owner: Symbol): Symbol = + cloneSymbolImpl(owner).setInfo(info.cloneInfo(owner)).setFlag(rawflags); + + /** Internal method to clone a symbol's implementation without flags or type + */ + def cloneSymbolImpl(owner: Symbol): Symbol; + +// Access to related symbols -------------------------------------------------- + + /** The next enclosing class */ + def enclClass: Symbol = if (isClass) this else owner.enclClass; + + /** The next enclosing method */ + def enclMethod: Symbol = if (isMethod) this else owner.enclMethod; + + /** The primary constructor of a class */ + def primaryConstructor: Symbol = { + var constr: Symbol = NoSymbol; + val syms = info.members.lookupAll(nme.CONSTRUCTOR); + while (syms.hasNext) constr = syms.next; + constr + } + + /** The self symbol of a class with explicit self type, or else the symbol itself. + */ + def thisSym: Symbol = this; + + /** The type of `this' in a class, or else the type of the symbol itself. */ + final def typeOfThis = thisSym.tpe; + + /** Sets the type of `this' in a class */ + def typeOfThis_=(tp: Type): unit = throw new Error("typeOfThis cannot be set for " + this); + + /** If symbol is a class, the type this.type in this class, otherwise NoPrefix */ + def thisType: Type = NoPrefix; + + /** Return every accessor of a primary constructor parameter in this case class */ + final def caseFieldAccessors: List[Symbol] = { + assert(isClass && hasFlag(CASE)); + info.members.toList.filter(sym => sym.isMethod && sym.hasFlag(PARAMACCESSOR)) + } + + /** The symbol accessed by this accessor function. + */ + final def accessed: Symbol = { + assert((rawflags & ACCESSOR) != 0); + val name1 = if (name.endsWith(nme._EQ)) name.subName(0, name.length - nme._EQ.length) + else name; + owner.info.lookup(name1.toString() + "$") + } + + /** The class with the same name in the same package as this module or + * case class factory + */ + final def linkedClass: Symbol = { + if (!owner.isPackageClass) NoSymbol + else { + val clazz = owner.info.lookup(name.toTypeName); + if (clazz.rawInfo == NoType) NoSymbol else clazz + } + } + + /** The module or case class factory with the same name in the same + * package as this class. + */ + final def linkedModule: Symbol = { + if (!owner.isPackageClass) NoSymbol + else { + val module = owner.info.lookup(name.toTermName).withFlag(MODULE); + if (module.rawInfo == NoType) NoSymbol else module + } + } + + /** The module corresponding to this module class (note that this + * is not updated when a module is cloned). + */ + def sourceModule: Symbol = NoSymbol; + + /** The module class corresponding to this module. + */ + def moduleClass: Symbol = NoSymbol; + + /** The symbol overridden by this symbol in given base class */ + final def overriddenSymbol(base: Symbol): Symbol = + base.info.lookupNonPrivate(name).matching(owner.thisType, info); + + /** The symbol overriding this symbol in given subclass */ + final def overridingSymbol(base: Symbol): Symbol = + base.info.lookupNonPrivate(name).matching(base.thisType, base.tpe.memberType(this)); + +// ToString ------------------------------------------------------------------- + + /** A tag which (in the ideal case) uniquely identifies class symbols */ + final def tag: int = name.toString().hashCode(); + + /** The simple name of this Symbol (this is always a term name) */ + final def simpleName: Name = + if (isConstructor && !settings.debug.value) owner.name.toTermName else name; + + /** String representation of symbol's definition key word */ + final def keyString: String = + if (isClass) + if (hasFlag(TRAIT)) + if (hasFlag(JAVA)) "interface" else "trait" + else "class" + else if (isType && !hasFlag(PARAM)) "type" + else if (isVariable) "var" + else if (isPackage) "package" + else if (isModule) "object" + else if (isMethod) "def" + else if (isTerm && (!hasFlag(PARAM) || hasFlag(PARAMACCESSOR))) "val" + else ""; + + /** String representation of symbol's kind */ + final def kindString: String = + if (isPackageClass) + if (settings.debug.value) "package class" else "package" + else if (isAnonymousClass) "<template>" + else if (isRefinementClass) "" + else if (isModuleClass) "singleton class" + else if (isClass) + if ((rawflags & TRAIT) != 0) "trait" else "class" + else if (isType) "type" + else if (isVariable) "variable" + else if (isPackage) "package" + else if (isModule) "object" + else if (isConstructor) "constructor" + else if (isMethod) "method" + else if (isTerm) "value" + else ""; + + /** String representation of symbol's simple name. + * If !settings.debug translates expansions of operators back to operator symbol. + * E.g. $eq => =. + * If settings.uniquId adds id. + */ + final def nameString: String = + simpleName.decode + idString; + + /** String representation of symbol's full name with `separator' + * between class names. + * Never translates expansions of operators back to operator symbol. + * Never adds id. + */ + final def fullNameString(separator: char): String = + if (owner.isRoot) simpleName.toString() + else owner.fullNameString(separator) + separator + simpleName; + + final def fullNameString: String = fullNameString('.'); + + /** If settings.uniqid is set, the symbol's id, else "" */ + final def idString: String = + if (settings.uniqid.value) "#" + id else ""; + + /** String representation, including symbol's kind + * e.g., "class Foo", "method Bar". + */ + override def toString(): String = + compose(List(kindString, nameString)); + + /** String representation of location. */ + final def locationString: String = + if (owner.isClass && + (!owner.isAnonymousClass && !owner.isRefinementClass || settings.debug.value)) + " in " + (if (owner.isModuleClass) owner.sourceModule else owner) + else ""; + + /** String representation of symbol's definition following its name */ + final def infoString(tp: Type): String = { + def typeParamsString: String = tp match { + case PolyType(tparams, _) if (tparams.length != 0) => + (tparams map (.defString)).mkString("[", ",", "]") + case _ => + "" + } + if (isClass) + typeParamsString + " extends " + tp.resultType + else if (isAliasType) + typeParamsString + " = " + tp.resultType + else if (isAbstractType) + tp.match { + case TypeBounds(lo, hi, vu) => + (if (lo.symbol == AllClass) "" else " >: " + lo) + + (if (hi.symbol == AnyClass) "" else " <: " + hi) + + (if (vu.symbol == AnyClass) "" else " <% " + vu) + case _ => + "<: " + tp; + } + else if (isModule) + moduleClass.infoString(tp) + else + tp match { + case PolyType(tparams, res) => + typeParamsString + infoString(res) + case MethodType(pts, res) => + pts.mkString("(", ",", ")") + infoString(res) + case _ => + ": " + tp + } + } + + /** String representation of symbol's variance */ + private def varianceString: String = + if (variance > 0) "+" + else if (variance < 0) "-" + else ""; + + /** String representation of symbol's definition */ + final def defString: String = + compose(List(flagsToString(flags & SOURCEFLAGS), + keyString, + varianceString + nameString, + infoString(rawInfo))); + + /** Concatenate strings separated by spaces */ + private def compose(ss: List[String]): String = + ss.filter("" !=).mkString("", " ", ""); + } + + /** A class for term symbols */ + class TermSymbol(initOwner: Symbol, initPos: int, initName: Name) extends Symbol(initOwner, initPos, initName) { + override def isTerm = true; + override def alternatives: Iterator[Symbol] = + if (owner.isClass) owner.info.members.lookupAll(name) + else super.alternatives; + def cloneSymbolImpl(owner: Symbol): Symbol = + new TermSymbol(owner, pos, name); + } + + /** A class for module symbols */ + class ModuleSymbol(initOwner: Symbol, initPos: int, initName: Name, mclazz: ClassSymbol) extends TermSymbol(initOwner, initPos, initName) { + setFlag(MODULE | FINAL); + private val clazz: ClassSymbol = + if (mclazz != null) mclazz else new ModuleClassSymbol(this); + override def moduleClass: ClassSymbol = clazz; + override def cloneSymbolImpl(owner: Symbol): Symbol = + new ModuleSymbol(owner, pos, name, clazz); + } + + /** A class of type symbols. Alias and abstract types are direct instances + * of this class. Classes are instances of a subclass. + */ + class TypeSymbol(initOwner: Symbol, initPos: int, initName: Name) extends Symbol(initOwner, initPos, initName) { + override def isType = true; + private var tyconCache: Type = null; + private var tpeCache: Type = _; + private var valid: Phase = null; + override def tpe: Type = { + if (valid != phase) { + valid = phase; + tpeCache = typeRef(owner.thisType, this, typeParams map (.tpe)) + } + tpeCache + } + override def typeConstructor: Type = { + if (tyconCache == null) + tyconCache = typeRef(owner.thisType, this, List()); + tyconCache; + } + override def reset(completer: Type): unit = { + super.reset(completer); + valid = null; + tyconCache = null; + } + def cloneSymbolImpl(owner: Symbol): Symbol = + new TypeSymbol(owner, pos, name); + } + + /** A class for class symbols */ + class ClassSymbol(initOwner: Symbol, initPos: int, initName: Name) + extends TypeSymbol(initOwner, initPos, initName) { + private var thissym: Symbol = this; + override def isClass: boolean = true; + override def reset(completer: Type): unit = { + super.reset(completer); + thissym = this; + } + + /** the type this.type in this class */ + override val thisType: Type = ThisType(this); + + /** A symbol carrying the self type of the class as its type */ + override def thisSym: Symbol = thissym; + + /** Sets the self type of the class */ + override def typeOfThis_=(tp: Type): unit = + thissym = newThisSym(pos).setInfo(tp); + + override def cloneSymbolImpl(owner: Symbol): Symbol = { + assert(!isModuleClass); + val clone = new ClassSymbol(owner, pos, name); + if (thisSym != this) clone.typeOfThis = typeOfThis; + clone + } + } + + /** A class for module class symbols */ + class ModuleClassSymbol(module: ModuleSymbol) + extends ClassSymbol(module.owner, module.pos, module.name.toTypeName) { + setFlag(module.getFlag(MODULE2CLASSFLAGS) | MODULE | FINAL); + override def sourceModule = module; + } + + /** An object repreesenting a missing symbol */ + object NoSymbol extends Symbol(null, Position.NOPOS, nme.NOSYMBOL) { + super.setInfo(NoType); + override def setInfo(info: Type): Symbol = { assert(info == NoType); this } + override def enclClass: Symbol = this; + override def enclMethod: Symbol = this; + override def owner: Symbol = throw new Error(); + override def reset(completer: Type): unit = {} + override def alternatives: Iterator[Symbol] = Iterator.empty[Symbol]; + def cloneSymbolImpl(owner: Symbol): Symbol = throw new Error(); + } + + /** An exception for cyclic references of symbol definitions */ + case class CyclicReference(sym: Symbol, info: Type) extends TypeError("illegal cyclic reference involving " + sym); + + /** A class for type histories */ + private class TypeHistory(val start: Phase, val info: Type, val prev: TypeHistory); +} diff --git a/sources/scala/tools/nsc/symtab/Types.scala b/sources/scala/tools/nsc/symtab/Types.scala new file mode 100755 index 0000000000..e3faa45813 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/Types.scala @@ -0,0 +1,1499 @@ +package scala.tools.nsc.symtab; + +import scala.tools.util.Position; +import Flags._; + +abstract class Types: SymbolTable { + import definitions._; + + private var explainSwitch = false; + + val emptyTypeArray = new Array[Type](0); + + /** The base class for all types */ + trait Type { + + /** The symbol associated with the type */ + def symbol: Symbol = NoSymbol; + + /** The base type underlying a singleton type, + * identity on all other types */ + def singleDeref: Type = this; + + /** Widen from singleton type to its underlying non-singleton base type + * by applying one or more singleDeref steps, + * identity for all other types */ + def widen: Type = this; + + /** Map to a this type which is a subtype of this type. + */ + def narrow: Type = { + val reftpe = refinedType(this, commonOwner(this), EmptyScope); + ThisType(reftpe.symbol); + } + + /** Map a constant type to its underlying base type, + * identity for all other types */ + def deconst: Type = this; + + /** Map a parameterless method type to its result type + * identity for all other types */ + def derefDef: Type = match { + case PolyType(List(), restp) => restp + case _ => this + } + + /** For a TypeBounds type, itself; + * for a reference denoting an abstract type, its bounds, + * for all other types, a TypeBounds type all of whose bounds are this type. + * error for all other types */ + def bounds: TypeBounds = TypeBounds(this, this, this); + + /** For a class or intersection type, its parents. + * For a TypeBounds type, the parents of its hi bound. + * inherited by typerefs, singleton types, and refinement types, + * The empty list for all other types */ + def parents: List[Type] = List(); + + /** For a typeref or single-type, its prefix. NoType for all other types. */ + def prefix: Type = NoType; + + /** For a typeref, its arguments. The empty list for all other types */ + def typeArgs: List[Type] = List(); + + /** For a method or poly type, its result type, + * the type itself for all other types */ + def resultType: Type = this; + + /** For a method or poly type, the number of its value parameter sections, + * 0 for all other types */ + def paramSectionCount: int = 0; + + /** For a method or poly type, the types of its first value parameter section, + * the empty list for all other types */ + def paramTypes: List[Type] = List(); + + /** For a poly type, its type parameters, + * the empty list for all other types */ + def typeParams: List[Symbol] = List(); + + /** Is this type produced as a repair for an error? */ + def isError: boolean = this == ErrorType || symbol.isError; + + /** Does this type denote a stable reference (i.e. singleton type)? */ + def isStable: boolean = false; + + /** For a classtype or refined type, its members; + * inherited by subtypes and typerefs. + * The empty scope for all other types */ + def members: Scope = EmptyScope; + + /** An iterator that enumerates all members of this type and its base types + * Members of any type precede members of its base types in the ordering + * Members of parents of a type are enumerated right to left. */ + def rawMembersIterator: Iterator[Symbol] = Iterator.empty; + + /** An iterator that enumerates all members of this type + * (defined or inherited). + * Defined members of a type precede members inherited from its base types + * in the ordering. + * Members of parents of a type are enumerated right to left. */ + def allPublicMembersIterator: Iterator[Symbol] = + for (val sym <- rawMembersIterator; + !sym.hasFlag(PRIVATE) && (lookup(sym.name).alternatives contains sym)) + yield sym; + + /** The member with given name of this type, NoSymbol if none exists */ + def lookup(name: Name): Symbol = lookupNonPrivate(name); + + /** The non-private member with given name of this type, + * NoSymbol if none exists. */ + def lookupNonPrivate(name: Name): Symbol = NoSymbol; + + /** The least type instance of given class which is a supertype + * of this type */ + def baseType(clazz: Symbol): Type = NoType; + + /** This type as seen from prefix `pre' and class `clazz'. This means: + * Replace all thistypes of `clazz' or one of its subclasses by `pre' + * and instantiate all parameters by arguments of `pre'. + * Proceed analogously for thistypes referring to outer classes. */ + def asSeenFrom(pre: Type, clazz: Symbol): Type = + new AsSeenFromMap(pre, clazz) apply this; + + /** The info of `sym', seen as a member of this type. */ + def memberInfo(sym: Symbol): Type = + sym.info.asSeenFrom(this, sym.owner); + + /** The type of `sym', seen as a member of this type. */ + def memberType(sym: Symbol): Type = + sym.tpe.asSeenFrom(this, sym.owner); + + /** Substitute types `to' for occurrences of references to symbols `from' + * in this type. */ + def subst(from: List[Symbol], to: List[Type]): Type = + new SubstTypeMap(from, to) apply this; + + /** Substitute symbols `to' for occurrences of symbols `from' in this type. */ + def substSym(from: List[Symbol], to: List[Symbol]): Type = + new SubstSymMap(from, to) apply this; + + /** Substitute all occurrences of ThisType(from) in this type by `to' */ + def substThis(from: Symbol, to: Type): Type = + new SubstThisMap(from, to) apply this; + + /** Does this type contain a reference to this symbol? */ + def contains(sym: Symbol): boolean = { + val m = new ContainsMap(sym); + m(this); + m.result + } + + /** Is this type a subtype of that type? */ + def <:<(that: Type): boolean = + if (explainSwitch) explain("<", isSubType, this, that) + else this == that || isSubType(this, that); + + /** Is this type equivalent to that type? */ + def =:=(that: Type): boolean = + if (explainSwitch) explain("<", isSameType, this, that) + else this == that || isSameType(this, that); + + /** Does this type implement symbol `sym' with same or stronger type? */ + def specializes(sym: Symbol): boolean = + if (explainSwitch) explain("specializes", specializesSym, this, sym) + else specializesSym(this, sym); + + /** Is this type close enough to that type so that + * members with the two type would override each other? + * This means: + * - Either both types are polytypes with the same number of + * type parameters and their result types match after renaming + * corresponding type parameters + * - Or both types are method types with equivalent type parameter types + * and matching result types + * - Or both types are equivalent + * - Or phase.exactMatch is false and both types are neither method nor + * poly types. + */ + def matches(that: Type): boolean = + matchesType(this, that); + + /** The shortest sorted upwards closed array of types that contains + * this type as first element. + * + * A list or array of types ts is upwards closed if + * + * for all t in ts: + * for all typerefs p.s[args] such that t <: p.s[args] + * there exists a typeref p'.s[args'] in ts such that + * t <: p'.s['args] <: p.s[args], + * and + * for all singleton types p.s such that t <: p.s + * there exists a singleton type p'.s in ts such that + * t <: p'.s <: p.s + * + * Sorting is with respect to Symbol.isLess() on type symbols. + */ + def closure: Array[Type] = Predef.Array(this); + + /** The index of given class symbol in the closure of this type, -1 + * of no base type with gien class symbol exists */ + def closurePos(sym: Symbol): int = { + val cl = closure; + var lo = 0; + var hi = cl.length - 1; + while (lo <= hi) { + val mid = (lo + hi) / 2; + val clsym = cl(mid).symbol; + if (sym == clsym) return mid + else if (sym isLess clsym) hi = mid - 1 + else if (clsym isLess sym) lo = mid + 1 + else throw new Error() + } + -1 + } + + /** The erasure of this type. This is: + * - For a singleton or constant type, + * the erasure of its underlying base type + * - For a non-empty type intersection, + * the erasure of its first parent + * - For a polymorphic type, the erasure of its result type + * - for types Object, All, Any: AnyRef + * - for an abstract type or TypeBounds type, + * the erasure of its upper bound + * - for all other typerefs, the type without prefix or arguments + * - for a method type, the method type consistsing of + * erased parameter and result types. + * - for all other types, the type itself. + */ + def erasure: Type = this; + + /** If this is a polytype, a copy with cloned type parameters owned + * by `owner'. Identity for all other types. */ + def cloneInfo(owner: Symbol) = this; + + /** The representation of this type used as a prefix */ + def prefixString = toString() + "."; + + /** Get type of `this' symbol corresponding to this class typeref, extend + * homomorphically to results of function types and poly types. + * Identity for all other types. */ + def instanceType = this; + + /** Is this type completed (i.e. not a lazy type)? + */ + def isComplete: boolean = true; + + /** If this is a lazy type, assign a new type to `sym'. */ + def complete(sym: Symbol): unit = {} + } + +// Subclasses ------------------------------------------------------------ + + /** A mixin for types that carry a members scope + * (refinements and class types) + */ + abstract class TypeWithScope(scope: Scope) extends Type { + + override def members: Scope = scope; + + override def rawMembersIterator: Iterator[Symbol] = + scope.toList.elements append super.rawMembersIterator; + + override def lookup(name: Name): Symbol = { + val sym = scope lookup name; + if (sym != NoSymbol) sym else super.lookupNonPrivate(name) + } + + override def lookupNonPrivate(name: Name): Symbol = { + val sym = scope lookup name; + if (sym != NoSymbol && !sym.hasFlag(PRIVATE)) sym + else super.lookupNonPrivate(name); + } + + override def toString(): String = + super.toString() + members.toString(); + } + + /** A base class for types that defer some operations + * to their immediate supertype + */ + abstract trait SubType extends Type { + protected def supertype: Type; + override def parents: List[Type] = supertype.parents; + override def members: Scope = supertype.members; + override def rawMembersIterator: Iterator[Symbol] = + supertype.rawMembersIterator; + override def lookup(name: Name): Symbol = supertype lookup name; + override def lookupNonPrivate(name: Name): Symbol = + supertype lookupNonPrivate name; + override def baseType(clazz: Symbol): Type = supertype.baseType(clazz); + override def closure: Array[Type] = supertype.closure; + override def erasure: Type = supertype.erasure; + } + + /** A base class for types that represent a single value + * (single-types and this-types) + */ + abstract trait SingletonType extends SubType { + override def singleDeref: Type; + protected def supertype: Type = singleDeref; + override def isStable: boolean = true; + override def widen: Type = singleDeref.widen; + override def closure: Array[Type] = addClosure(this, supertype.closure); + } + + /** An object representing an erroneous type */ + case object ErrorType extends Type { + override def members: Scope = new ErrorScope(NoSymbol); + override def lookupNonPrivate(name: Name): Symbol = members lookup name; + override def baseType(clazz: Symbol): Type = this; + override def toString(): String = "<error>"; + override def narrow: Type = this; + } + + /** An object representing an unknown type */ + case object WildcardType extends Type { + override def toString(): String = "?" + } + + /** An object representing a non-existing type */ + case object NoType extends Type { + override def toString(): String = "<notype>" + } + + /** An object representing a non-existing prefix */ + case object NoPrefix extends Type { + override def isStable: boolean = true; + override def prefixString = ""; + } + + /** A class for this-types of the form <sym>.this.type + */ + case class ThisType(sym: Symbol) extends SingletonType { + override def symbol = sym; + override def singleDeref: Type = sym.typeOfThis; + override def toString(): String = + if (!settings.debug.value && + (sym.isAnonymousClass || sym.isRefinementClass)) "this.type" + else sym.nameString + ".this.type"; + override def narrow: Type = this; + } + + /** A class for singleton types of the form <prefix>.<sym.name>.type. + * Cannot be created directly; one should always use + * `singleType' for creation. + */ + abstract case class SingleType(pre: Type, sym: Symbol) extends SingletonType { + private var singleDerefCache: Type = _; + private var valid: Phase = null; + override def singleDeref: Type = { + if (valid != phase) { + valid = phase; + singleDerefCache = pre.memberType(sym).resultType; + } + singleDerefCache + } + override def symbol = sym; + override def prefix: Type = pre; + override def toString(): String = + pre.prefixString + sym.nameString + ".type"; + } + + /** A class for the bounds of abstract types and type parameters + */ + case class TypeBounds(lo: Type, hi: Type, vu: Type) extends SubType { + protected def supertype: Type = hi; + override def bounds: TypeBounds = this; + def containsType(that: Type) = lo <:< that && that <:< hi; + } + + /** A common base class for intersection types and class types + */ + abstract class TypeIntersection(override val parents: List[Type]) extends Type { + override def lookupNonPrivate(name: Name): Symbol = { + def lookIn(ps: List[Type]): Symbol = ps match { + case List() => NoSymbol + case p::ps1 => + val sym = p lookupNonPrivate name; + val sym1 = lookIn(ps1); + if (sym1 == NoSymbol + || + !sym.hasFlag(DEFERRED) && sym1.hasFlag(DEFERRED) + || + sym.hasFlag(DEFERRED) == sym1.hasFlag(DEFERRED) && + (sym.owner isSubClass sym1.owner)) sym + else sym1 + } + lookIn(parents); + } + + private var closureCache: Array[Type] = _; + private var valid: Phase = null; + + override def closure: Array[Type] = { + if (valid != phase) { + valid = phase; + closureCache = null; + try { + closureCache = computeClosure; + } catch { + case ex: MalformedClosure => + throw new MalformedType( + "the type intersection " + this + " is malformed" + + "\n --- because ---\n" + ex.getMessage()) + } + } + if (closureCache == null) + throw new TypeError("illegal cyclic reference involving " + symbol); + closureCache; + } + + protected def computeClosure: Array[Type]; + + override def baseType(sym: Symbol): Type = { + val index = closurePos(sym); + if (index >= 0) closure(index) else NoType; + } + + /* + override def baseType(clazz: Symbol): Type = + glb(parents map (.baseType(clazz)) filter (.!=(NoType))); + */ + + override def rawMembersIterator: Iterator[Symbol] = + for (val parent <- parents.reverse.elements; + val sym <- parent.rawMembersIterator) yield sym; + + override def erasure: Type = + if (parents.isEmpty) this else parents.head.erasure; + + override def toString(): String = + parents.mkString("", " with ", ""); + } + + /** A class representing intersection types of the form + * <parents_0> with ... with <parents_n> + */ + case class IntersectionType(_parents: List[Type]) + extends TypeIntersection(_parents) { + def computeClosure: Array[Type] = glbArray(parents map (.closure)); + } + + /** A class representing a refinement + * Cannot be created directly; + * one should always use `refinedType' for creation. + */ + abstract case class RefinedType(base: Type, refinement: Scope) + extends SubType with TypeWithScope(refinement) { + protected def supertype: Type = base; + override def narrow: Type = symbol.thisType; + } + + /** A class representing a class info + */ + case class ClassInfoType(_parents: List[Type], defs: Scope, clazz: Symbol) + extends TypeIntersection(_parents) with TypeWithScope(defs) { + + override def symbol: Symbol = clazz; + + def computeClosure: Array[Type] = + addClosure(clazz.tpe, glbArray(parents map (.closure))); + + override def toString(): String = + super[TypeWithScope].toString(); + } + + class PackageClassInfoType(defs: Scope, clazz: Symbol) extends ClassInfoType(List(), defs, clazz); + + /** A class representing a constant type */ + case class ConstantType(base: Type, value: Any) + extends SingletonType { + override def symbol: Symbol = base.symbol; + override def singleDeref: Type = base; + override def deconst: Type = base; + override def toString(): String = base.toString() + "(" + value + ")"; + } + + /** A class for named types of the form <prefix>.<sym.name>[args] + * Cannot be created directly; one should always use `typeRef' for creation. + */ + abstract case class TypeRef(pre: Type, sym: Symbol, args: List[Type]) extends Type { + assert(!sym.isAbstractType || pre.isStable || pre.isError); + + private def transform(tp: Type): Type = + tp.asSeenFrom(pre, sym.owner).subst(sym.typeParams, args); + + private def transform(cl: Array[Type]): Array[Type] = { + val cl1 = new Array[Type](cl.length); + var i = 0; + while (i < cl.length) { cl1(i) = transform(cl(i)); i = i + 1 } + cl1 + } + + override def symbol = sym; + + override def bounds: TypeBounds = + if (sym.isAbstractType) transform(sym.info.bounds).asInstanceOf[TypeBounds] + else super.bounds; + + override def parents: List[Type] = sym.info.parents map transform; + + override def prefix: Type = pre; + + override def typeArgs: List[Type] = args; + + override def members: Scope = sym.info.members; + + override def rawMembersIterator: Iterator[Symbol] = + sym.info.rawMembersIterator; + + override def lookup(name: Name): Symbol = sym.info.lookup(name); + + override def lookupNonPrivate(name: Name): Symbol = + sym.info.lookupNonPrivate(name); + + override def baseType(clazz: Symbol): Type = + if (sym == clazz) this + else if (sym.isClass) transform(sym.info.baseType(clazz)) + else pre.memberInfo(sym).baseType(clazz); + + override def closure: Array[Type] = + if (sym.isAbstractType) addClosure(this, bounds.hi.closure) + else transform(sym.info.closure); + + override def instanceType: Type = + if (sym.thisSym != sym) transform(sym.typeOfThis) + else this; + + override def erasure: Type = + if (sym.isAbstractType || sym.isAliasType) sym.info.erasure + else if (sym == ObjectClass || + sym == AllClass || + sym == AllRefClass || + sym == AnyRefClass) AnyClass.tpe + else typeRef(NoPrefix, sym, List()); + + override def toString(): String = + if (!settings.debug.value && sym == RepeatedParamClass && !args.isEmpty) + args(0).toString() + "*" + else pre.prefixString + sym.nameString + + (if (args.isEmpty) "" else args.mkString("[", ",", "]")); + } + + /** A class representing a method type with parameters. + */ + case class MethodType(override val paramTypes: List[Type], + override val resultType: Type) extends Type { + + override def paramSectionCount: int = resultType.paramSectionCount + 1; + + override def instanceType: Type = { + val res = resultType.instanceType; + if (res eq resultType) this else MethodType(paramTypes, res) + } + + override def erasure = { + val pts = map1(paramTypes, t: Type => t.erasure); + val res = resultType.erasure; + if ((pts eq paramTypes) && (res eq resultType)) this + else MethodType(pts, res) + } + + override def toString(): String = paramTypes.mkString("(", ",", ")") + resultType; + } + + /** A class representing a polymorphic type or, if tparams.length == 0, + * a parameterless method type. + */ + case class PolyType(override val typeParams: List[Symbol], + override val resultType: Type) extends Type { + + override def paramSectionCount: int = resultType.paramSectionCount; + + override def paramTypes: List[Type] = resultType.paramTypes; + + override def instanceType: Type = { + val res = resultType.instanceType; + if (res eq resultType) this else PolyType(typeParams, res) + } + + override def erasure = resultType.erasure; + + override def toString(): String = + (if (typeParams.isEmpty) "=> " else typeParams.mkString("[", ",", "]")) + + resultType; + + override def cloneInfo(owner: Symbol) = { + val tparams = typeParams map (.cloneSymbol(owner)); + for (val tparam <- tparams) + tparam.setInfo(tparam.info.substSym(typeParams, tparams)); + PolyType(tparams, resultType.substSym(typeParams, tparams)) + } + } + + /** A class representing a type variable + */ + case class TypeVar(origin: Type, constr: TypeConstraint) extends Type { + + override def symbol = origin.symbol; + + override def toString(): String = + if (constr.inst == NoType) "?" + origin else constr.inst.toString(); + } + + /** A class representing an as-yet unevaluated type. + */ + abstract class LazyType extends Type { + override def isComplete: boolean = false; + override def complete(sym: Symbol): unit; + } + + /** A class representing a lazy type with known type parameters + */ + class LazyPolyType(tparams: List[Symbol], restp: Type) extends LazyType { + override def complete(sym: Symbol): unit = { + restp.complete(sym); + sym.setInfo(PolyType(tparams, sym.info)) + } + } + +// Creators --------------------------------------------------------------- + + /** Rebind symbol `sym' to an overriding member in type `pre' */ + private def rebind(pre: Type, sym: Symbol): Symbol = { + val owner = sym.owner; + if (owner.isClass && owner != pre.symbol && !sym.isFinal) { + val rebind = pre lookupNonPrivate sym.name; + if (rebind == NoSymbol) sym else rebind + } else sym + } + + /** The canonical creator for single-types */ + def singleType(pre: Type, sym: Symbol): SingleType = { + if (!pre.isStable && !pre.isError) + throw new MalformedType(pre, sym.name.toString()); + new SingleType(pre, rebind(pre, sym)) {} + } + + /** The canonical creator for typerefs */ + def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = { + val sym1 = if (sym.isAbstractType) rebind(pre, sym) else sym; + if (sym1.isAbstractType && !pre.isStable && !pre.isError) + throw new MalformedType(pre, sym.nameString); + if (sym1.isAliasType && sym1.typeParams.length == args.length) { + if (sym1.hasFlag(LOCKED)) + throw new TypeError("illegal cyclic reference involving " + sym1); + sym1.setFlag(LOCKED); + val result = sym1.info.asSeenFrom(pre, sym1.owner).subst(sym1.typeParams, args); + sym1.resetFlag(LOCKED); + result + } else { + new TypeRef(pre, sym1, args) {} + } + } + + /** the canonical creator for a refined type with an initially empty scope */ + def refinedType(base: Type, owner: Symbol): RefinedType = + refinedType(base, owner, new Scope); + + /** the canonical creator for a refined type with a given scope */ + def refinedType(base: Type, owner: Symbol, members: Scope): RefinedType = { + val clazz = owner.newRefinementClass(Position.NOPOS); + val result = new RefinedType(base, members) { + override def symbol: Symbol = clazz + } + clazz.setInfo(result); + result + } + + /** A creator for intersection type where intersections of a single type are + * replaced by the type itself. */ + def intersectionType(tps: List[Type]): Type = tps match { + case List(tp) => tp + case _ => IntersectionType(tps) + } + + /** A creator for type applications */ + def appliedType(tycon: Type, args: List[Type]): Type = tycon match { + case TypeRef(pre, sym, args1) => + if (args eq args1) tycon + else typeRef(pre, sym, args) + case ErrorType => tycon + } + +// Helper Classes --------------------------------------------------------- + + /** A class expressing upper and lower bounds constraints + * for type variables, as well as their instantiations */ + class TypeConstraint { + var lobounds: List[Type] = List(); + var hibounds: List[Type] = List(); + var inst: Type = NoType; + + def instantiate(tp: Type): boolean = + if (lobounds.forall(.<:<(tp)) && hibounds.forall(tp.<:<)) { + inst = tp; true + } else false; + } + + /** A prototype for mapping a function over all possible types + */ + trait TypeMap extends Function1[Type, Type] { + // deferred inherited: def apply(tp: Type): Type + + /** Map this function over given type */ + def mapOver(tp: Type): Type = tp match { + case ErrorType | WildcardType | NoType | NoPrefix | TypeVar(_, _) | ThisType(_) => + tp + case SingleType(pre, sym) => + val pre1 = this(pre); + if (pre1 eq pre) tp + else singleType(pre1, sym) + case ConstantType(base, value) => + val base1 = this(base); + if (base1 eq base) tp + else ConstantType(base1, value) + case TypeRef(pre, sym, args) => + val pre1 = this(pre); + val args1 = map1(args, this); + if ((pre1 eq pre) && (args1 eq args)) tp + else typeRef(pre1, sym, args1) + case TypeBounds(lo, hi, vu) => + val lo1 = this(lo); + val hi1 = this(hi); + val vu1 = this(vu); + if ((lo1 eq lo) && (hi1 eq hi) && (vu1 eq vu)) tp + else TypeBounds(lo1, hi1, vu1) + case RefinedType(base, refinement) => + val base1 = this(base); + val refinement1 = mapOver(refinement); + if ((base1 eq base) && (refinement1 eq refinement)) tp + else { + val result = refinedType(base1, tp.symbol.owner); + val syms1 = refinement1.toList; + for (val sym <- syms1) + result.members.enter(sym.cloneSymbol(result.symbol)); + val syms2 = result.members.toList; + val resultThis = ThisType(result.symbol); + for (val sym <- syms2) + sym.setInfo(sym.info.substSym(syms1, syms2).substThis(tp.symbol, resultThis)); + result + } + case IntersectionType(parents) => + val parents1 = map1(parents, this); + if (parents1 eq parents) tp + else IntersectionType(parents1) + case MethodType(paramtypes, result) => + val paramtypes1 = map1(paramtypes, this); + val result1 = this(result); + if ((paramtypes1 eq paramtypes) && (result1 eq result)) tp + else MethodType(paramtypes1, result1) + case PolyType(tparams, result) => + val tparams1 = mapOver(tparams); + val result1 = this(result); + if ((tparams1 eq tparams) && (result1 eq result)) tp + else PolyType(tparams1, result1) + case _ => + throw new Error("mapOver inapplicable for " + tp); + } + + /** Map this function over given scope */ + private def mapOver(scope: Scope): Scope = { + val elems = scope.toList; + val elems1 = mapOver(elems); + if (elems1 eq elems) scope + else new Scope(elems1) + } + + /** Map this function over given list of symbols */ + private def mapOver(syms: List[Symbol]): List[Symbol] = { + val infos = syms map (.info); + val infos1 = map1(infos, this); + if (infos1 eq infos) syms + else { + val syms1 = syms map (.cloneSymbol); + List.map2(syms1, infos1) + ((sym1, info1) => sym1.setInfo(info1.substSym(syms, syms1))) + } + } + } + + /** A map to compute the asSeenFrom method */ + class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap { + def apply(tp: Type): Type = + if (pre == NoType || !clazz.isClass) tp + else tp match { + case ThisType(sym) => + def toPrefix(pre: Type, clazz: Symbol): Type = + if (pre == NoType || !clazz.isClass) tp + else if ((sym isSubClass clazz) && (pre.widen.symbol isSubClass sym)) pre + else toPrefix(pre.baseType(clazz).prefix, clazz.owner); + toPrefix(pre, clazz) + case SingleType(pre, sym) => + try { + mapOver(tp) + } catch { + case ex: MalformedType => apply(tp.singleDeref) // todo: try needed? + } + case TypeRef(prefix, sym, args) if (sym.isTypeParameter) => + def toInstance(pre: Type, clazz: Symbol): Type = + if (pre == NoType || !clazz.isClass) tp + else { + val symclazz = sym.owner; + def throwError = + throw new Error("" + tp + " in " + symclazz + + "cannot be instantiated from " + pre.widen); + def instParam(ps: List[Symbol], as: List[Type]): Type = + if (ps.isEmpty) throwError + else if (sym eq ps.head) as.head + else instParam(ps.tail, as.tail); + if (symclazz == clazz && (pre.widen.symbol isSubClass symclazz)) + pre.baseType(symclazz) match { + case TypeRef(_, basesym, baseargs) => + instParam(basesym.typeParams, baseargs); + case _ => + throwError + } + else toInstance(pre.baseType(clazz).prefix, clazz.owner) + } + toInstance(pre, clazz) + case _ => + mapOver(tp) + } + } + + /** A base class to compute all substitutions */ + abstract class SubstMap[T](from: List[Symbol], to: List[T]) extends TypeMap { + + /** Are sym1, sym1 the same. Can be tunded by subclasses */ + protected def matches(sym: Symbol, sym1: Symbol): boolean = sym eq sym1; + + /** Map target to type, can be tuned by subclasses */ + protected def toType(fromtp: Type, t: T): Type; + + def apply(tp: Type): Type = { + def subst(sym: Symbol, from: List[Symbol], to: List[T]): Type = + if (from.isEmpty) tp + else if (matches(from.head, sym)) toType(tp, to.head) + else subst(sym, from.tail, to.tail); + tp match { + case TypeRef(NoPrefix, sym, _) => + subst(sym, from, to) + case SingleType(NoPrefix, sym) => + subst(sym, from, to) + case PolyType(tparams, restp) => + assert(!(tparams exists (from contains))); + mapOver(tp) + case _ => + mapOver(tp) + } + } + } + + /** A map to implement the substSym method */ + class SubstSymMap(from: List[Symbol], to: List[Symbol]) + extends SubstMap(from, to) { + protected def toType(fromtp: Type, sym: Symbol) = fromtp match { + case TypeRef(pre, _, args) => typeRef(pre, sym, args) + case SingleType(pre, _) => singleType(pre, sym) + } + } + + /** A map to implement the subst method */ + class SubstTypeMap(from: List[Symbol], to: List[Type]) + extends SubstMap(from, to) { + protected def toType(fromtp: Type, tp: Type) = tp; + } + + /** A map to implement the substThis method */ + class SubstThisMap(from: Symbol, to: Type) extends TypeMap { + def apply(tp: Type): Type = tp match { + case ThisType(sym) if (sym == from) => to + case _ => mapOver(tp) + } + } + + /** A map to convert every occurrence of a wildcard type to a fresh + * type variable */ + object wildcardToTypeVarMap extends TypeMap { + def apply(tp: Type): Type = tp match { + case WildcardType => TypeVar(tp, new TypeConstraint) + case _ => mapOver(tp) + } + } + + /** A map to implement the contains method */ + class ContainsMap(sym: Symbol) extends TypeMap { + var result = false; + def apply(tp: Type): Type = { + if (!result) { + tp match { + case TypeRef(_, sym1, _) if (sym == sym1) => result = true + case SingleType(_, sym1) if (sym == sym1) => result = true + case _ => mapOver(tp) + } + } + tp + } + } + + /** A map to compute the most deeply nested owner that contains all the symbols + * of thistype or prefixless typerefs/singletype occurrences in given type */ + object commonOwnerMap extends TypeMap { + var result: Symbol = _; + def init = { result = NoSymbol } + def apply(tp: Type): Type = tp match { + case ThisType(sym) => + register(sym); + tp + case TypeRef(NoPrefix, sym, args) => + register(sym.owner); + for (val arg <- args) apply(arg); + tp + case SingleType(NoPrefix, sym) => + register(sym.owner); + tp + case _ => + mapOver(tp) + } + private def register(sym: Symbol) = + if (result == NoSymbol || (result isNestedIn sym)) result = sym + else assert(result == sym || (sym isNestedIn result)); + } + + /** Equivalent to (xs map f), except that the same (wrt eq) input list + * (or its suffix) is returned if the function `f' is the identity + * on all elements of the list (or the suffix). */ + def map1[T <: AnyRef](xs: List[T], f: T => T): List[T] = xs match { + case List() => xs + case hd :: tl => + val hd1 = f(hd); + val tl1 = map1(tl, f); + if ((hd1 eq hd) && (tl1 eq tl)) xs + else hd1 :: tl1 + } + +// Helper Methods ------------------------------------------------------------- + + /** Do tp1 and tp2 denote equivalent types? */ + def isSameType(tp1: Type, tp2: Type): boolean = (tp1 eq tp2) || { + Pair(tp1, tp2) match { + case Pair(ErrorType, _) + | Pair(WildcardType, _) + | Pair(_, ErrorType) + | Pair(_, WildcardType) => + true + case Pair(NoType, _) + | Pair(NoPrefix, _) + | Pair(_, NoType) + | Pair(_, NoPrefix) => + false + case Pair(ThisType(sym1), ThisType(sym2)) => + sym1 == sym2 + case Pair(SingleType(pre1, sym1), SingleType(pre2, sym2)) + if (sym1 == sym2 && pre1 =:= pre2) => + true + case Pair(SingleType(pre1, sym1), ThisType(sym2)) + if (sym1.isModule && + sym1.moduleClass == sym2 && + pre1 =:= sym2.owner.thisType) => + true + case Pair(ThisType(sym1), SingleType(pre2, sym2)) + if (sym2.isModule && + sym2.moduleClass == sym1 && + pre2 =:= sym1.owner.thisType) => + true + case Pair(ConstantType(base1, value1), ConstantType(base2, value2)) => + base1 =:= base2 && value1 == value2 + case Pair(TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => + sym1 == sym2 && pre1 =:= pre2 && isSameTypes(args1, args2) + case Pair(IntersectionType(parents1), IntersectionType(parents2)) => + isSameTypes(parents1, parents2) + case Pair(RefinedType(base1, ref1), RefinedType(base2, ref2)) => + def isSubScope(s1: Scope, s2: Scope): boolean = s2.toList.forall { + sym2 => + val sym1 = s1.lookup(sym2.name); + sym1.info =:= sym2.info.substThis(sym2.owner, sym1.owner.thisType) + } + base1 =:= base2 && isSubScope(ref1, ref2) && isSubScope(ref2, ref1) + case Pair(MethodType(pts1, res1), MethodType(pts2, res2)) => + pts1.length == pts2.length && + isSameTypes(pts1, pts2) && + res1 =:= res2 + case Pair(PolyType(tparams1, res1), PolyType(tparams2, res2)) => + tparams1.length == tparams2.length && + List.forall2(tparams1, tparams2) + ((p1, p2) => p1.info =:= p2.info.substSym(tparams2, tparams1)) && + res1 =:= res2.substSym(tparams2, tparams1) + case Pair(TypeBounds(lo1, hi1, vu1), TypeBounds(lo2, hi2, vu2)) => + lo1 =:= lo2 && hi1 =:= hi2 && vu1 =:= vu2 + case Pair(TypeVar(_, constr1), _) => + if (constr1.inst != NoType) constr1.inst =:= tp2 + else constr1 instantiate (wildcardToTypeVarMap(tp2)) + case Pair(_, TypeVar(_, constr2)) => + if (constr2.inst != NoType) tp1 =:= constr2.inst + else constr2 instantiate (wildcardToTypeVarMap(tp1)) + case Pair(SingleType(_, _), _) + if (tp2.isStable && tp1.singleDeref =:= tp2) => + true + case Pair(_, SingleType(_, _)) + if (tp1.isStable && tp1 =:= tp2.singleDeref) => + true + case _ => + false + } + } + + /** Are tps1 and tps2 lists of pairwise equivalent types? */ + def isSameTypes(tps1: List[Type], tps2: List[Type]): boolean = + tps1.length == tps2.length && + List.forall2(tps1, tps2)((tp1, tp2) => tp1 =:= tp2); + + /** Does tp1 conform to tp2? */ + def isSubType(tp1: Type, tp2: Type): boolean = (tp1 eq tp2) || { + Pair(tp1, tp2) match { + case Pair(ErrorType, _) + | Pair(WildcardType, _) + | Pair(_, ErrorType) + | Pair(_, WildcardType) => + true + case Pair(NoType, _) + | Pair(NoPrefix, _) + | Pair(_, NoType) + | Pair(_, NoPrefix) => + false + case Pair(ThisType(_), ThisType(_)) + | Pair(ThisType(_), SingleType(_, _)) + | Pair(SingleType(_, _), ThisType(_)) + | Pair(SingleType(_, _), SingleType(_, _)) + | Pair(ConstantType(_, _), ConstantType(_, _)) => + tp1 =:= tp2 + case Pair(TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => + def isSubArgs(tps1: List[Type], tps2: List[Type], + tparams: List[Symbol]): boolean = { + tps1.isEmpty && tps2.isEmpty + || + !tps1.isEmpty && !tps2.isEmpty && + (if (tparams.head.hasFlag(COVARIANT)) tps1.head <:< tps2.head + else if (tparams.head.hasFlag(CONTRAVARIANT)) tps2.head <:< tps1.head + else tps1.head =:= tps2.head) && + isSubArgs(tps1.tail, tps2.tail, tparams.tail) + } + sym1 == sym2 && (pre1 <:< pre2) && + isSubArgs(args1, args2, sym1.typeParams) + || + sym1.isAbstractType && (tp1.bounds.hi <:< tp2) + || + sym2.isAbstractType && (tp1 <:< tp2.bounds.lo) + || + sym2.isClass && + ({ val base = tp1 baseType sym2; !(base eq tp1) && (base <:< tp2) }) + || + sym1 == AllClass + || + sym1 == AllRefClass && sym2 != AllClass && tp2 <:< AnyRefClass.tpe + case Pair(MethodType(pts1, res1), MethodType(pts2, res2)) => + pts1.length == pts2.length && + isSameTypes(pts1, pts2) && (res1 <:< res2) + case Pair(PolyType(tparams1, res1), PolyType(tparams2, res2)) => + tparams1.length == tparams2.length && + List.forall2(tparams1, tparams2) + ((p1, p2) => p2.info.substSym(tparams2, tparams1) <:< p1.info) && + res1 <:< res2.substSym(tparams2, tparams1) + case Pair(TypeBounds(lo1, hi1, vu1), TypeBounds(lo2, hi2, vu2)) => + lo2 <:< lo1 && hi1 <:< hi2 && vu1 <:< vu2 + case Pair(_, TypeVar(_, constr2)) => + if (constr2.inst != NoType) tp1 <:< constr2.inst + else { constr2.lobounds = tp1 :: constr2.lobounds; true } + case Pair(TypeVar(_, constr1), _) => + if (constr1.inst != NoType) constr1.inst <:< tp2 + else { constr1.hibounds = tp2 :: constr1.hibounds; true } + case Pair(_, IntersectionType(parents2)) => + parents2 forall (tp1.<:<) + case Pair(_, RefinedType(base2, ref2)) => + tp1 <:< base2 && (ref2.toList forall (tp1 specializes)) + case Pair(IntersectionType(parents1), _) => + parents1 exists (.<:<(tp2)) + case Pair(ThisType(_), _) + | Pair(SingleType(_, _), _) + | Pair(ConstantType(_, _), _) + | Pair(RefinedType(_, _), _) => + tp1.singleDeref <:< tp2 + case Pair(TypeRef(pre1, sym1, args1), _) => + sym1 == AllClass && tp2 <:< AnyClass.tpe + || + sym1 == AllRefClass && tp2.symbol != AllClass && tp2 <:< AnyRefClass.tpe + case _ => + false + } + } + + /** Are tps1 and tps2 lists of equal length such that all elements + * of tps1 conform to corresponding elements of tps2? */ + def isSubTypes(tps1: List[Type], tps2: List[Type]): boolean = + tps1.length == tps2.length && + List.forall2(tps1, tps2)((tp1, tp2) => tp1 <:< tp2); + + /** Does type `tp' implement symbol `sym' with same or stronger type? + * Exact only if `sym' is a member of some refinement type, otherwise + * we might return false negatives */ + def specializesSym(tp: Type, sym: Symbol): boolean = + tp.symbol == AllClass || + tp.symbol == AllRefClass && (sym.owner isSubClass AnyRefClass) || + (tp.lookupNonPrivate(sym.name).alternatives exists + (alt => sym == alt || specializesSym(tp.narrow, alt, ThisType(sym.owner), sym))); + + /** Does member `sym1' of `tp1' have a stronger type than member `sym2' of `tp2'? */ + private def specializesSym(tp1: Type, sym1: Symbol, tp2: Type, sym2: Symbol): boolean = { + val info1 = tp1.memberInfo(sym1); + val info2 = tp2.memberInfo(sym2).substThis(tp2.symbol, tp1); + sym2.isTerm && + info1 <:< info2 || + sym2.isAbstractType && + (info2.bounds containsType info1) || + sym2.isAliasType && + tp2.memberType(sym2) =:= tp1.memberType(sym1) + } + + /** A function implementing tp1 matches tp2 */ + private def matchesType(tp1: Type, tp2: Type): boolean = Pair(tp1, tp2) match { + case Pair(MethodType(pts1, res1), MethodType(pts2, res2)) => + isSameTypes(pts1, pts2) && (res1 matches res2) + case Pair(PolyType(tparams1, res1), PolyType(tparams2, res2)) => + tparams1.length == tparams2.length && + (res1 matches res2.substSym(tparams2, tparams1)) + case Pair(MethodType(_, _), _) | Pair(PolyType(_, _), _) => + false + case _ => + !phase.exactMatch || tp1 =:= tp2 + } + + private def addClosure(tp: Type, cl: Array[Type]): Array[Type] = { + val cl1 = new Array[Type](cl.length + 1); + cl1(0) = tp; + System.arraycopy(cl, 0, cl1, 1, cl.length); + cl + } + +// Lubs and Glbs --------------------------------------------------------- + + private val recLimit = 10; + private var recCount = 0; + private var giveUp: boolean = _; + + /** Return op(tps), but give up if level of recursion is greater than + * recLimit */ + private def limitRecursion(tps: List[Type], boundkind: String, + op: List[Type] => Type): Type = + if (recCount == recLimit) { + giveUp = true; + AnyClass.tpe + } else { + if (recCount == 0) giveUp = false; + val result = try { + recCount = recCount + 1; + op(tps) + } finally { + recCount = recCount - 1 + } + if (recCount == 0 && giveUp) { + throw new TypeError("failure to compute " + boundkind + + " bound of types " + + tps.mkString("", " and ", ";\n") + + "an approximation is: " + result + ";\n" + + "additional type annotations are needed"); + } + result + } + + /** The greatest sorted upwards closed lower bound of a list of lists of + * types relative to the following ordering <= between lists of types: + * + * xs <= ys iff forall y in ys exists x in xs such that x <: y + * + * @See closure for a definition of sorted and upwards closed. + */ + private def glbList(tss: List[List[Type]]): List[Type] = { + val tss1 = tss filter (ts => !ts.isEmpty); + if (tss1.isEmpty) List() + else if (tss1.tail.isEmpty) tss.head + else { + val ts0 = tss1 map (.head); + val sym = minSym(ts0); + val ts1 = elimSuper(ts0 filter (.symbol.==(sym))); + mergePrefixAndArgs(ts1, -1) match { + case Some(tp0) => + tp0 :: glbList(tss1 map (ts => if (ts.head.symbol == sym) ts.tail else ts)) + case None => + throw new MalformedClosure(ts1) + } + } + } + + /** The greatest sorted upwards closed lower bound of a list of closures. + * @See glbList for more explanations. + */ + private def glbArray(tss: List[Array[Type]]): Array[Type] = { + val tss1 = tss map (ts: Array[Type] => List.fromArray(ts)); + val glbs = glbList(tss1); + val result = new Array[Type](glbs.length); + var i = 0; + for (val x <- glbs.elements) { result(i) = x; i = i + 1; } + result; + // Predef.Array(glbs: _*); + } + + /** The least sorted upwards closed upper bound of a non-empty list + * of lists of types. + * @See glbList for more explanations. */ + private def lubList(tss: List[List[Type]]): List[Type] = + if (tss.tail.isEmpty) tss.head + else if (tss exists (.isEmpty)) List() + else { + val ts0 = tss map (.head); + val sym = minSym(ts0); + if (ts0 forall (t => t.symbol == sym)) + mergePrefixAndArgs(elimSub(ts0), 1).toList ::: lubList(tss map (.tail)) + else + lubList(tss map (ts => if (ts.head.symbol == sym) ts.tail else ts)) + } + + /** The least sorted upwards closed upper bound of a non-empty list + * of closures. + * @See lubList for more explanations. */ + private def lubArray(tss: List[Array[Type]]): Array[Type] = + Predef.Array(lubList(tss map (ts: Array[Type] => List.fromArray(ts))): _* ); + + /** The minimal symbol (wrt Symbol.isLess) of a list of types */ + private def minSym(tps: List[Type]): Symbol = + (tps.head.symbol /: tps.tail) { + (sym1, tp2) => if (tp2.symbol isLess sym1) tp2.symbol else sym1 + } + + /** A minimal type which has a given array of types as its closure */ + private def spanningType(ts: Array[Type]): Type = { + def spanningTypes(ts: List[Type]): List[Type] = ts match { + case List() => List() + case first :: rest => + first :: spanningTypes( + rest filter (t => !first.symbol.isSubClass(t.symbol))) + } + intersectionType(spanningTypes(List.fromArray(ts))) + } + + /** Eliminate from list of types all elements which are a supertype + * of some other element of the list. */ + private def elimSuper(ts: List[Type]): List[Type] = + ts filter (t => !(ts exists (t1 => t1 <:< t))); + + /** Eliminate from list of types all elements which are a subtype + * of some other element of the list. */ + private def elimSub(ts: List[Type]): List[Type] = + ts filter (t => !(ts exists (t1 => t <:< t1))); + + /** The least upper bound wrt <:< of a list of types */ + def lub(ts: List[Type]): Type = { + def lub0(ts0: List[Type]): Type = elimSub(ts0) match { + case List() => AllClass.tpe + case List(t) => t + case ts @ PolyType(tparams, _) :: _ => + PolyType( + List.map2(tparams, List.transpose(matchingBounds(ts, tparams))) + ((tparam, bounds) => tparam.cloneSymbol.setInfo(glb(bounds))), + lub0(ts map (.resultType))) + case ts @ MethodType(pts, _) :: rest => + MethodType(pts, lub0(matchingRestypes(ts, pts))) + case ts => + val closures: List[Array[Type]] = ts map (.closure); + val lubBaseTypes: Array[Type] = lubArray(closures); + val lubBase = spanningType(lubBaseTypes); + val lubType = refinedType(lubBase, commonOwner(ts)); + val lubThisType = lubType.symbol.thisType; + val narrowts = ts map (.narrow); + def lubsym(proto: Symbol): Symbol = { + val prototp = lubThisType.memberInfo(proto); + val syms = narrowts map (t => + t.lookup(proto.name) + .matching(NoPrefix, prototp.substThis(lubThisType.symbol, t))); + val symtypes = List.map2(narrowts, syms) + ((t, sym) => t.memberInfo(sym).substThis(t.symbol, lubThisType)); + if (syms contains NoSymbol) + NoSymbol + else if (proto.isTerm) + proto.cloneSymbol.setInfo(lub(symtypes)) + else if (symtypes.tail forall (symtypes.head =:=)) + proto.cloneSymbol.setInfo(symtypes.head) + else { + def lubBounds(bnds: List[TypeBounds]): TypeBounds = + TypeBounds( + glb(bnds map (.lo)), lub(bnds map (.hi)), lub(bnds map (.vu))); + proto.owner.newAbstractType(proto.pos, proto.name) + .setInfo(lubBounds(symtypes map (.bounds))) + } + } + def refines(tp: Type, sym: Symbol) = { + val sym1 = tp.lookupNonPrivate(sym.name); + (sym1 != NoSymbol) && + (sym1.alternatives forall ( + alt => !specializesSym(lubThisType, sym, tp, alt))) + } + for (val sym <- lubBase.allPublicMembersIterator) + // add a refinement symbol for all non-class members of lubBase + // which are refined by every type in ts. + if (!sym.isClass && (narrowts forall (t => refines(t, sym)))) + addMember(lubThisType, lubType.members, lubsym(sym)); + if (lubType.members.isEmpty) lubBase else lubType; + } + limitRecursion(ts, "least upper", lub0); + } + + /** The greatest lower bound wrt <:< of a list of types */ + def glb(ts: List[Type]): Type = { + def glb0(ts0: List[Type]): Type = elimSuper(ts0) match { + case List() => AnyClass.tpe + case List(t) => t + case ts @ PolyType(tparams, _) :: _ => + PolyType( + List.map2(tparams, List.transpose(matchingBounds(ts, tparams))) + ((tparam, bounds) => tparam.cloneSymbol.setInfo(lub(bounds))), + glb0(ts map (.resultType))) + case ts @ MethodType(pts, _) :: rest => + MethodType(pts, glb0(matchingRestypes(ts, pts))) + case ts => + try { + val glbBase = intersectionType(ts); + val glbType = refinedType(glbBase, commonOwner(ts)); + val glbThisType = glbType.symbol.thisType; + def glbsym(proto: Symbol): Symbol = { + val prototp = glbThisType.memberInfo(proto); + val syms = for (val t <- ts; + val alt <- List.fromIterator(t.lookup(proto.name).alternatives); + glbThisType.memberInfo(alt) matches prototp) yield alt; + val symtypes = syms map glbThisType.memberInfo; + assert(!symtypes.isEmpty); + proto.cloneSymbol.setInfo( + if (proto.isTerm) glb(symtypes) + else { + def isTypeBound(tp: Type) = tp match { + case TypeBounds(_, _, _) => true + case _ => false + } + def glbBounds(bnds: List[Type]): TypeBounds = { + val lo = lub(bnds map (.bounds.lo)); + val hi = glb(bnds map (.bounds.hi)); + if (lo <:< hi) TypeBounds(lo, hi, glb(bnds map (.bounds.vu))) + else throw new MalformedClosure(bnds) + } + val symbounds = symtypes filter isTypeBound; + var result: Type = + if (symbounds.isEmpty) + TypeBounds(AllClass.tpe, AnyClass.tpe, AnyClass.tpe) + else glbBounds(symbounds); + for (val t <- symtypes; !isTypeBound(t)) + if (result.bounds containsType t) result = t + else throw new MalformedClosure(symtypes); + result + }) + } + for (val t <- ts; val sym <- t.allPublicMembersIterator) + if (!(sym.isClass || (glbThisType specializes sym))) + addMember(glbThisType, glbType.members, glbsym(sym)); + if (glbType.members.isEmpty) glbBase else glbType; + } catch { + case _: MalformedClosure => + if (ts forall (t => t <:< AnyRefClass.tpe)) AllRefClass.tpe + else AllClass.tpe + } + } + limitRecursion(ts, "greatest lower", glb0) + } + + /** The most deeply nested owner that contains all the symbols + * of thistype or prefixless typerefs/singletype occurrences in given type */ + private def commonOwner(t: Type): Symbol = { + commonOwnerMap.init; + commonOwnerMap.apply(t); + commonOwnerMap.result + } + + /** The most deeply nested owner that contains all the symbols + * of thistype or prefixless typerefs/singletype occurrences in given list of types */ + private def commonOwner(tps: List[Type]): Symbol = { + commonOwnerMap.init; + map1(tps, commonOwnerMap); + commonOwnerMap.result + } + + /** Compute lub (if variance == 1) or glb (if variance == 0) of given list of types + * `tps'. All types in `tps' are typerefs or singletypes with the same symbol. + * Return Some(x) if the computation succeeds with result `x'. + * Return None if the computuation fails. + */ + private def mergePrefixAndArgs(tps: List[Type], variance: int): Option[Type] = tps match { + case List(tp) => + Some(tp) + case TypeRef(_, sym, _) :: rest => + val pres = tps map (.prefix); + val pre = if (variance == 1) lub(pres) else glb(pres); + val argss = tps map (.typeArgs); + val args = + List.map2(sym.typeParams, List.transpose(argss)) + ((tparam, as) => + if (tparam.variance == variance) lub(as) + else if (tparam.variance == -variance) glb(as) + else NoType); + try { + if (args contains NoType) None + else Some(typeRef(pre, sym, args)) + } catch { + case ex: MalformedType => None + } + case SingleType(_, sym) :: rest => + val pres = tps map (.prefix); + val pre = if (variance == 1) lub(pres) else glb(pres); + try { + Some(singleType(pre, sym)) + } catch { + case ex: MalformedType => None + } + } + + /** Make symbol `sym' a member of scope `members' where `thistp' is the narrowed + * owner type of the scope */ + private def addMember(thistp: Type, members: Scope, sym: Symbol): unit = { + if (!(thistp specializes sym)) { + if (sym.isTerm) + for (val alt <- members.lookup(sym.name).alternatives) + if (specializesSym(thistp, sym, thistp, alt)) + members.unlink(alt); + members.enter(sym) + } + } + + /** All types in list must be polytypes with type parameter lists of + * same length as tparams. + * Returns list of list of bounds infos, where corresponding type + * parameters are renamed to tparams. + */ + private def matchingBounds(tps: List[Type], tparams: List[Symbol]): List[List[Type]] = + tps map { + case PolyType(tparams1, _) if (tparams1.length == tparams.length) => + tparams1 map (tparam => tparam.info.substSym(tparams1, tparams)) + case _ => + throw new Error("lub/glb of incompatible types: " + tps.mkString("", " and ", "")) + } + + /** All types in list must be method types with equal parameter types. + * Returns list of their result types. + */ + private def matchingRestypes(tps: List[Type], pts: List[Type]): List[Type] = + tps map { + case MethodType(pts1, res) if (isSameTypes(pts1, pts)) => + res + case _ => + throw new Error("lub/glb of incompatible types: " + tps.mkString("", " and ", "")) + } + +// Errors and Diagnostics --------------------------------------------------------- + + /** An exception signalling a type error */ + class TypeError(msg: String) extends java.lang.Error(msg); + + /** An exception signalling a malformed type */ + class MalformedType(msg: String) extends TypeError(msg) { + def this(pre: Type, tp: String) = this("malformed type: " + pre + "#" + tp); + } + + /** An exception signalling a malformed closure */ + class MalformedClosure(ts: List[Type]) + extends TypeError("no common type instance of base types " + + ts.mkString("", " and ", "") + " exists"); + + /** An exception signalling a variance annotation/usage conflict */ + class VarianceError(msg: String) extends TypeError(msg); + + /** The current indentation string for traces */ + private var indent: String = ""; + + /** Perform operation `p' on arguments `tp1', `arg2' and print trace of computation */ + private def explain[T](op: String, p: (Type, T) => boolean, tp1: Type, arg2: T): boolean = { + System.out.println(indent + tp1 + " " + op + " " + arg2 + "?"); + indent = indent + " "; + val result = p(tp1, arg2); + indent = indent.substring(0, indent.length() - 2); + System.out.println(indent + result); + result + } + + /** If option `explaintypes' is set, print a subtype trace for `found' <: `required' */ + def explainTypes(found: Type, required: Type): unit = + if (settings.explaintypes.value) { + val s = explainSwitch; + explainSwitch = true; + found <:< required; + explainSwitch = s + } +} diff --git a/sources/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala b/sources/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala new file mode 100644 index 0000000000..433ae327b8 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala @@ -0,0 +1,45 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scala.tools.nsc.symtab.classfile; + +object ClassfileConstants { + + val JAVA_MAGIC = 0xCAFEBABE; + val JAVA_MAJOR_VERSION = 45; + val JAVA_MINOR_VERSION = 3; + + val JAVA_ACC_PUBLIC = 0x0001; + val JAVA_ACC_PRIVATE = 0x0002; + val JAVA_ACC_PROTECTED = 0x0004; + val JAVA_ACC_STATIC = 0x0008; + val JAVA_ACC_FINAL = 0x0010; + val JAVA_ACC_SUPER = 0x0020; + val JAVA_ACC_SYNCHRONIZED = 0x0020; + val JAVA_ACC_VOLATILE = 0x0040; + val JAVA_ACC_BRIDGE = 0x0040; + val JAVA_ACC_TRANSIENT = 0x0080; + val JAVA_ACC_NATIVE = 0x0100; + val JAVA_ACC_INTERFACE = 0x0200; + val JAVA_ACC_ABSTRACT = 0x0400; + val JAVA_ACC_STRICT = 0x0800; + val JAVA_ACC_SYNTHETIC = 0x1000; + + val CONSTANT_UTF8 = 1; + val CONSTANT_UNICODE = 2; + val CONSTANT_INTEGER = 3; + val CONSTANT_FLOAT = 4; + val CONSTANT_LONG = 5; + val CONSTANT_DOUBLE = 6; + val CONSTANT_CLASS = 7; + val CONSTANT_STRING = 8; + val CONSTANT_FIELDREF = 9; + val CONSTANT_METHODREF = 10; + val CONSTANT_INTFMETHODREF = 11; + val CONSTANT_NAMEANDTYPE = 12; +} diff --git a/sources/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/sources/scala/tools/nsc/symtab/classfile/ClassfileParser.scala new file mode 100755 index 0000000000..ee16209bdb --- /dev/null +++ b/sources/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -0,0 +1,388 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scala.tools.nsc.symtab.classfile; + +import scala.tools.util._; +import java.io.IOException; + +abstract class ClassfileParser { + + val global: Global; + import global._; + + import ClassfileConstants._; + import Flags._; + + private var in: AbstractFileReader = _; // the class file + private var clazz: Symbol = _; // the class symbol containing dynamic members + private var statics: Symbol = _; // the module class symbol containing static members + private var classMembers: Scope = _; // the scope of all dynamic members + private var staticMembers: Scope = _; // the scope of all static members + private var pool: ConstantPool = _; // the classfile's constant pool + private var isScala: boolean = _; // does class file describe a scala class? + private var hasMeta: boolean = _; // does class file contain jaco meta attribute?s + private var busy: boolean = false; // lock to detect recursive reads + + private object metaParser extends MetaParser { + val global: ClassfileParser.this.global.type = ClassfileParser.this.global + } + + private object unpickle extends UnPickle { + val global: ClassfileParser.this.global.type = ClassfileParser.this.global + } + + def parse(file: AbstractFile, root: Symbol): unit = { + assert(!busy); + busy = true; + this.in = new AbstractFileReader(file); + if (root.isModule) { + this.clazz = root.linkedClass; + this.statics = root.moduleClass + } else { + this.clazz = root; + this.statics = root.linkedModule.moduleClass; + } + this.isScala = false; + this.hasMeta = false; + try { + parseHeader; + this.pool = new ConstantPool; + parseClass() + } catch { + case e: RuntimeException => + if (settings.debug.value) e.printStackTrace(); + throw new IOException("class file '" + in.path + "' is broken") + } + busy = false + } + + private def parseHeader: unit = { + val magic = in.nextInt(); + if (magic != JAVA_MAGIC) + throw new IOException("class file '" + in.path + "' " + + "has wrong magic number 0x" + Integer.toHexString(magic) + + ", should be 0x" + Integer.toHexString(JAVA_MAGIC)); + val minorVersion = in.nextChar(); + val majorVersion = in.nextChar(); + if ((majorVersion < JAVA_MAJOR_VERSION) || + ((majorVersion == JAVA_MAJOR_VERSION) && + (minorVersion < JAVA_MINOR_VERSION))) + throw new IOException("class file '" + in.path + "' " + + "has unknown version " + + majorVersion + "." + minorVersion + + ", should be at least " + + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION); + + } + + class ConstantPool { + private val len = in.nextChar(); + private val starts = new Array[int](len); + private val values = new Array[Object](len); + private val internalized = new Array[Name](len); + { var i = 1; + while (i < starts.length) { + starts(i) = in.bp; + i = i + 1; + in.nextByte() match { + case CONSTANT_UTF8 | CONSTANT_UNICODE => + in.skip(in.nextChar()); + case CONSTANT_CLASS | CONSTANT_STRING => + in.skip(2); + case CONSTANT_FIELDREF | CONSTANT_METHODREF | CONSTANT_INTFMETHODREF | CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT => + in.skip(4); + case CONSTANT_LONG | CONSTANT_DOUBLE => + in.skip(8); + i = i + 1 + case _ => + errorBadTag(in.bp - 1); + } + } + } + + def getName(index: int): Name = { + if (index <= 0 || len <= index) errorBadIndex(index); + var name = values(index).asInstanceOf[Name]; + if (name == null) { + val start = starts(index); + if (in.buf(start) != CONSTANT_UTF8) errorBadTag(start); + val len = in.getChar(start + 1); + val cs = new Array[char](len); + val defined = UTF8Codec.decode(in.buf, start + 3, cs, 0, len); + name = newTermName(cs, 0, defined); + values(index) = name; + } + name + } + + def getExternalName(index: int): Name = { + if (index <= 0 || len <= index) errorBadIndex(index); + if (internalized(index) == null) { + internalized(index) = getName(index).replace('/', '.') + } + internalized(index) + } + + def getClassSymbol(index: int): Symbol = { + if (index <= 0 || len <= index) errorBadIndex(index); + var c = values(index).asInstanceOf[Symbol]; + if (c == null) { + val start = starts(index); + if (in.buf(start) != CONSTANT_CLASS) errorBadTag(start); + val name = getExternalName(in.getChar(start + 1)); + c = definitions.getClass(name); + values(index) = c; + } + c + } + + def getType(index: int): Type = + sigToType(getExternalName(index)); + + def getSuperClass(index: int): Symbol = + if (index == 0) definitions.AnyClass else getClassSymbol(index); + + def getLiteral(index: int): Any = { + if (index <= 0 || len <= index) errorBadIndex(index); + var value = values(index); + if (value == null) { + val start = starts(index); + value = in.buf(start) match { + case CONSTANT_STRING => + getName(in.getChar(start + 1)).toString() + case CONSTANT_INTEGER => + in.getInt(start + 1) + case CONSTANT_FLOAT => + in.getFloat(start + 1) + case CONSTANT_LONG => + in.getLong(start + 1) + case CONSTANT_DOUBLE => + in.getDouble(start + 1) + case _ => + errorBadTag(start); + } + values(index) = value; + } + value + } + + /** Throws an exception signaling a bad constant index. */ + private def errorBadIndex(index: int) = + throw new RuntimeException("bad constant pool index: " + index); + + /** Throws an exception signaling a bad tag at given address. */ + private def errorBadTag(start: int) = + throw new RuntimeException("bad constant pool tag " + in.buf(start) + " at byte " + start); + } + + private def sigToType(name: Name): Type = { + var index = 0; + val end = name.length; + def paramsigs2types: List[Type] = + if (name(index) == ')') { index = index + 1; List() } + else sig2type :: paramsigs2types; + def sig2type: Type = { + val tag = name(index); index = index + 1; + tag match { + case 'B' => definitions.ByteClass.tpe + case 'C' => definitions.CharClass.tpe + case 'D' => definitions.DoubleClass.tpe + case 'F' => definitions.FloatClass.tpe + case 'I' => definitions.IntClass.tpe + case 'J' => definitions.LongClass.tpe + case 'S' => definitions.ShortClass.tpe + case 'V' => definitions.UnitClass.tpe + case 'Z' => definitions.BooleanClass.tpe + case 'L' => + val start = index; + while (name(index) != ';') { index = index + 1 } + val end = index; + index = index + 1; + definitions.getClass(name.subName(start, end)).tpe + case '[' => + while ('0' <= name(index) && name(index) <= '9') index = index + 1; + appliedType(definitions.ArrayClass.tpe, List(sig2type)) + case '(' => + MethodType(paramsigs2types, sig2type) + } + } + sig2type + } + + def parseClass(): unit = { + val jflags = in.nextChar(); + var sflags = transFlags(jflags); + if ((sflags & DEFERRED) != 0) sflags = sflags & ~DEFERRED | ABSTRACT; + val c = pool.getClassSymbol(in.nextChar()); + if (c != clazz) + throw new IOException("class file '" + in.path + "' contains wrong " + clazz); + val superType = pool.getSuperClass(in.nextChar()).tpe; + val ifaceCount = in.nextChar(); + val parents = superType :: + (for (val i <- List.range(0, ifaceCount)) + yield pool.getSuperClass(in.nextChar()).tpe); + classMembers = new Scope(); + staticMembers = new Scope(); + val classInfo = ClassInfoType(parents, classMembers, clazz); + val staticInfo = ClassInfoType(List(), staticMembers, statics); + + val curbp = in.bp; + skipMembers(); // fields + skipMembers(); // methods + parseAttributes(clazz, classInfo); + if (!isScala) { + clazz.setFlag(sflags); + if (!hasMeta) { + clazz.setInfo(classInfo); + statics.setInfo(staticInfo); + } + statics.sourceModule.setInfo(statics.tpe); + in.bp = curbp; + val fieldCount = in.nextChar(); + for (val i <- Iterator.range(0, fieldCount)) parseField(); + val methodCount = in.nextChar(); + for (val i <- Iterator.range(0, methodCount)) parseMethod(); + } + } + + def parseField(): unit = { + val jflags = in.nextChar(); + var sflags = transFlags(jflags); + if ((sflags & FINAL) != 0) sflags = sflags | MUTABLE; + if ((sflags & PRIVATE) != 0) { + in.skip(4); skipAttributes(); + } else { + val name = pool.getName(in.nextChar()); + val info = pool.getType(in.nextChar()); + val sym = getOwner(jflags) + .newValue(Position.NOPOS, name).setFlag(sflags).setInfo(info); + parseAttributes(sym, info); + getScope(jflags).enter(sym); + } + } + + def parseMethod(): unit = { + val jflags = in.nextChar(); + var sflags = transFlags(jflags); + if ((sflags & JAVA_ACC_BRIDGE) != 0) sflags = sflags | PRIVATE; + if ((sflags & PRIVATE) != 0) { + in.skip(4); skipAttributes(); + } else { + val name = pool.getName(in.nextChar()); + val info = pool.getType(in.nextChar()); + val sym = getOwner(jflags) + .newMethod(Position.NOPOS, name).setFlag(sflags).setInfo(info); + parseAttributes(sym, info); + getScope(jflags).enter(sym); + } + } + + def parseAttributes(sym: Symbol, symtype: Type): unit = { + def parseAttribute(): unit = { + val attrName = pool.getName(in.nextChar()); + val attrLen = in.nextInt(); + attrName match { + case nme.SyntheticATTR => + sym.setFlag(SYNTHETIC); + in.skip(attrLen) + case nme.BridgeATTR => + sym.setFlag(BRIDGE); + in.skip(attrLen) + case nme.DeprecatedATTR => + sym.setFlag(DEPRECATED); + in.skip(attrLen) + case nme.ConstantValueATTR => + def cast(value: Any, tp: Type): Any = { + val s = symtype.symbol; + if (s == definitions.ByteClass) value.asInstanceOf[byte] + else if (s == definitions.ShortClass) value.asInstanceOf[short] + else if (s == definitions.CharClass) value.asInstanceOf[char] + else if (s == definitions.IntClass) value.asInstanceOf[int] + else if (s == definitions.LongClass) value.asInstanceOf[long] + else if (s == definitions.FloatClass) value.asInstanceOf[float] + else if (s == definitions.DoubleClass) value.asInstanceOf[double] + else if (s == definitions.UnitClass) () + else if (s == definitions.BooleanClass) value.asInstanceOf[int] != 0 + else if (s == definitions.StringClass) value.asInstanceOf[String] + else value + } + val value = pool.getLiteral(in.nextChar()); + sym.setInfo(ConstantType(symtype, cast(value, symtype))) + case nme.InnerClassesATTR => + parseInnerClasses() + case nme.ScalaSignatureATTR => + //unpickle.parse(in.nextBytes(attrLen), clazz, statics.sourceModule); + //this.isScala = true; + case nme.JacoMetaATTR => + val meta = pool.getName(in.nextChar()).toString().trim(); + metaParser.parse(meta, sym, symtype); + this.hasMeta = true; + case _ => + in.skip(attrLen) + } + } + def parseInnerClasses(): unit = { + for (val i <- Iterator.range(0, in.nextChar())) { + val innerIndex = in.nextChar(); + val outerIndex = in.nextChar(); + val nameIndex = in.nextChar(); + val jflags = in.nextChar(); + if (innerIndex != 0 && outerIndex != 0 && nameIndex != 0 && + (jflags & (JAVA_ACC_PUBLIC | JAVA_ACC_PROTECTED)) != 0 && + pool.getClassSymbol(outerIndex) == sym) { + val innerAlias = getOwner(jflags) + .newAliasType(Position.NOPOS, pool.getName(nameIndex).toTypeName) + .setInfo(pool.getClassSymbol(innerIndex).tpe); + getScope(jflags).enter(innerAlias); + } + } + } + val attrCount = in.nextChar(); + for (val i <- Iterator.range(0, attrCount)) parseAttribute() + } + + def skipAttributes(): unit = { + val attrCount = in.nextChar(); + for (val i <- Iterator.range(0, attrCount)) { + in.skip(2); in.skip(in.nextInt()) + } + } + + def skipMembers(): unit = { + val memberCount = in.nextChar(); + for (val i <- Iterator.range(0, memberCount)) { + in.skip(6); skipAttributes() + } + } + + private def getOwner(flags: int): Symbol = + if ((flags & JAVA_ACC_STATIC) != 0) statics else clazz; + + private def getScope(flags: int): Scope = + if ((flags & JAVA_ACC_STATIC) != 0) staticMembers else classMembers; + + private def transFlags(flags: int): int = { + var res = 0; + if ((flags & JAVA_ACC_PRIVATE) != 0) + res = res | PRIVATE + else if ((flags & JAVA_ACC_PROTECTED) != 0) + res = res | PROTECTED + else if ((flags & JAVA_ACC_PUBLIC) == 0) + res = res | PRIVATE; + if ((flags & JAVA_ACC_ABSTRACT) != 0) + res = res | DEFERRED; + if ((flags & JAVA_ACC_FINAL) != 0) + res = res | FINAL; + if ((flags & JAVA_ACC_INTERFACE) != 0) + res = res | TRAIT | ABSTRACT; + if ((flags & JAVA_ACC_SYNTHETIC) != 0) + res = res | SYNTHETIC; + res | JAVA; + } +} diff --git a/sources/scala/tools/nsc/symtab/classfile/MetaParser.scala b/sources/scala/tools/nsc/symtab/classfile/MetaParser.scala new file mode 100755 index 0000000000..dfa8804bf7 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/classfile/MetaParser.scala @@ -0,0 +1,152 @@ +/** $Id: MetaParser.scala +*/ +package scala.tools.nsc.symtab.classfile; + +import java.util.{StringTokenizer, NoSuchElementException} +import scala.collection.mutable.ListBuffer; +import scala.tools.util.Position; + +abstract class MetaParser{ + + val global: Global; + import global._; + + private var scanner: StringTokenizer = _; + private var owner: Symbol = _; + private var ownertype: Type = _; + private var token: String = _; + private var locals: Scope = null; + + def parse(meta: String, sym: Symbol, symtype: Type): unit = { + //System.out.println("parse meta for " + sym + ":" + meta + ", locals = " + locals);//DEBUG + this.scanner = new StringTokenizer(meta, "()[], \t<;", true); + this.owner = sym; + this.ownertype = symtype; + nextToken(); + if (token == "class") parseClass() + else if (token == "method") parseMethod() + else if (token == "field") parseField() + else if (token == "constr") parseConstr() + else owner.setInfo(symtype); + } + + protected def nextToken(): unit = + try { + do { token = scanner.nextToken().trim() } while (token.length() == 0) + } catch { + case ex: NoSuchElementException => token = "" + } + + protected def parseType(): Type = { + val str = token; + nextToken(); + val sym = locals.lookup(newTypeName(str)); + if (sym != NoSymbol) sym.tpe + else { + val tp = definitions.getClass(str).tpe; + if (token != "[") tp + else { + val args = new ListBuffer[Type]; + do { + nextToken(); args append parseType(); + } while (token == ","); + nextToken(); + appliedType(tp, args.toList) + } + } + } + + protected def parseTypeParam(): Symbol = { + val vflag = + if (token == "+") { nextToken(); Flags.COVARIANT } + else if (token == "-") { nextToken(); Flags.CONTRAVARIANT } + else 0; + assert(token.startsWith("?")); + val sym = owner.newTypeParameter(Position.NOPOS, newTypeName(token)) + .setFlag(vflag) + .setInfo(TypeBounds( + definitions.AllClass.tpe, + definitions.AnyClass.tpe, + definitions.AnyClass.tpe)); + locals enter sym; + nextToken(); + sym + } + + protected def parseTypeParams(): List[Symbol] = { + nextToken(); + val syms = new ListBuffer[Symbol]; + if (token != "]") { + syms append parseTypeParam(); + while (token == ",") { + nextToken(); syms append parseTypeParam(); + } + } + assert(token == "]"); + syms.toList + } + + protected def parseParams(): List[Type] = { + nextToken(); + val tps = new ListBuffer[Type]; + if (token != ")") { + tps append parseType(); + while (token == ",") { + nextToken(); tps append parseType(); + } + } + assert(token == ")"); + tps.toList + } + + protected def parseClass(): unit = { + locals = new Scope(); + def parse(): Type = { + nextToken(); + if (token == "[") { + PolyType(parseTypeParams(), parse()) + } else if (token == "extends") { + val tps = new ListBuffer[Type]; + do { + nextToken(); tps append parseType() + } while (token == "with"); + ownertype match { + case ClassInfoType(parents, defs, clazz) => + ClassInfoType(tps.toList, defs, clazz) + } + } else ownertype + } + owner.setInfo(parse()); + assert(token == ";") + } + + protected def parseMethod(): unit = { + val globals = locals; + locals = if (locals == null) new Scope() else new Scope(locals); + def parse(): Type = { + nextToken(); + if (token == "[") PolyType(parseTypeParams(), parse()) + else if (token == "(") MethodType(parseParams(), parse()) + else parseType() + } + owner.setInfo(parse()); + locals = globals; + assert(token == ";") + } + + protected def parseField(): unit = { + nextToken(); + owner.setInfo(parseType()); + assert(token == ";") + } + + protected def parseConstr(): unit = { + def parse(): Type = { + nextToken(); + if (token == "(") MethodType(parseParams(), parse()) + else definitions.UnitClass.tpe + } + owner.setInfo(parse()); + assert(token == ";") + } +} diff --git a/sources/scala/tools/nsc/symtab/classfile/Pickle.scala b/sources/scala/tools/nsc/symtab/classfile/Pickle.scala new file mode 100644 index 0000000000..37ba9cf47e --- /dev/null +++ b/sources/scala/tools/nsc/symtab/classfile/Pickle.scala @@ -0,0 +1,6 @@ +package scala.tools.nsc.symtab.classfile; + +/*************************************************** + * Symbol table attribute format: see EntryTags.java + */ +class Pickle {} diff --git a/sources/scala/tools/nsc/symtab/classfile/UnPickle.scala b/sources/scala/tools/nsc/symtab/classfile/UnPickle.scala new file mode 100755 index 0000000000..07ab81ff67 --- /dev/null +++ b/sources/scala/tools/nsc/symtab/classfile/UnPickle.scala @@ -0,0 +1,477 @@ +//import scalac.{symtab => scalac_symtab} + +package scala.tools.nsc.symtab.classfile { + +//import scalac_symtab.Modifiers; +//import scalac_symtab.EntryTags._; +import java.io.PrintStream; +import scala.tools.util.{Position, UTF8Codec}; +import java.lang.{Float, Double}; + +/*************************************************** + * Symbol table attribute format: see EntryTags.java + */ +abstract class UnPickle { + + val global: Global; + import global._; + + private var classRoot: Symbol = _; + private var moduleRoot: Symbol = _; + private var bytes: Array[byte] = _; + private var bp: int = _; + private var index: Array[int] = _; + private var entries: Array[Any] = _; + + def parse(bytes: Array[byte], clazz: Symbol, module: Symbol): unit = { + warning("cannot yet unpickle: " + clazz.fullNameString('.')); + } +}} +/* + this.classRoot = clazz; + this.moduleRoot = module; + this.bytes = bytes; + this.bp = 0; + if (settings.debug.value) global.log("unpickle " + classRoot + " and " + moduleRoot); + createIndex(); + if (settings.debug.value) printAll(System.out); + entries = new Array[Any](index.length); + for (val i <- Iterator.range(0, index.length)) { + if (isSymbolEntry(i)) getSymbol(i) + } + if (settings.debug.value) global.log("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug + } + + def readByte(): int = { + val x = bytes(bp); bp = bp + 1; x + } + + def readNat(): int = { + var b = 0; + var x = 0; + do { + b = readByte(); + x = (x << 7) + (b & 0x7f); + } while ((b & 0x80) != 0); + x + } + + def readLong(len: int): long = { + var x = 0L; + var i = 0; + while (i < len) { + x = (x << 8) + (readByte() & 0xff); + i = i + 1 + } + val leading = 64 - (len << 3); + x << leading >> leading + } + + private def at[T](start: int)(op: => T): T = { + val savedBp = bp; + bp = start; + val result = op; + bp = savedBp; + result + } + + private def createIndex(): unit = { + index = new Array[int](readNat()); + for (val i <- Iterator.range(0, index.length)) { + index(i) = readByte(); + bp = readNat() + bp + } + } + + def isTypeEntry(i: int): boolean = { + val tag = bytes(index(i)); + (firstTypeTag <= tag && tag <= lastTypeTag) || tag == NOpre; + } + + def isSymbolEntry(i: int): boolean = { + val tag = bytes(index(i)); + firstSymTag <= tag && tag <= lastSymTag + } + + def getName(i: int): Name = { + var name: Name = entries(i).asInstanceOf[Name]; + if (name == null) { + at(index(i)) { + val tag = readByte(); + val len = readNat(); + val cs = new Array[char](len); + val defined = UTF8Codec.decode(bytes, bp, cs, 0, len); + name = tag match { + case TERMname => newTermName(cs, 0, defined) + case TYPEname => newTypeName(cs, 0, defined) + case _ => errorBadSignature(""); + } + entries(i) = name + } + } + name + } + + def readNameRef(): Name = getName(readNat()); + + def getSymbol(i: int): Symbol = { + var sym: Symbol = entries(i).asInstanceOf[Symbol]; + if (sym == null) { + at(index(i)) { + val tag = readByte(); + val end = readNat() + bp; + tag match { + case NONEsym => + sym = NoSymbol; + entries(i) = sym + case EXTref | EXTMODCLASSref => + val name = readNameRef(); + val owner = + if (bp == end) definitions.RootClass + else { assert(bp < end); readSymbolRef() } + sym = + if (name.toTermName == nme.ROOT && owner == NoSymbol) { + assert(tag != EXTref); + global.definitions.RootClass + } else if (tag == EXTMODCLASSref) { + owner.info.lookup(name).moduleClass + } else { + owner.info.lookup(name) + } + entries(i) = sym; + if (sym == NoSymbol) + errorBadSignature( + "reference " + (if (name.isTypeName) "type " else "value ") + + name.decode + " of " + owner + " refers to nonexisting symbol."); + case _ => + assert(isSymbolEntry(i)); + val name = readNameRef(); + if (settings.debug.value) global.log("reading " + name + " at " + i); + val owner = readSymbolRef(); + if (entries(i) != null) + sym = entries(i).asInstanceOf[Symbol] + else { + val pflags = readNat(); + val inforef = readNat(); + var syminfo: Type = null; + tag match { + case TYPEsym => + sym = owner.newAbstractType(Position.NOPOS, name); + entries(i) = sym; + syminfo = new LazyBoundsTypeRef( + inforef, readNat(), (pflags & Modifiers.VIEWBOUND) != 0) + case ALIASsym => + sym = owner.newAliasType(Position.NOPOS, name); + entries(i) = sym; + syminfo = new LazyTypeRef(inforef, sym); + val constr = readSymbolRef(); + if (!constr.typeParams.isEmpty) + syminfo = new LazyPolyType( + constr.typeParams map (.cloneSymbol(sym)), + syminfo); + case CLASSsym => + sym = + if ((pflags & Modifiers.MODUL) != 0) { + val modulesym = readSymbolRef(); + modulesym.moduleClass + } else if (name == classRoot.name && owner == classRoot.owner) { + if (settings.debug.value) global.log("overwriting " + classRoot); + classRoot + } else { + owner.newClass(Position.NOPOS, name) + } + entries(i) = sym; + syminfo = new LazyTypeRef(inforef, sym); + sym.setTypeOfThis(new LazyTypeRef(readNat(), sym)); + val constr = readSymbolRef(); + if (!constr.typeParams.isEmpty) + syminfo = new LazyPolyType( + constr.typeParams map (.cloneSymbol(sym)), + syminfo); + case VALsym => + sym = + if (name == moduleRoot.name && owner == moduleRoot.owner) { + if (settings.debug.value) global.log("overwriting " + moduleRoot); + moduleRoot + } else if ((pflags & Modifiers.MODUL) != 0) { + owner.newModule(Position.NOPOS, name) + } else { + if (name == nme.CONSTRUCTOR && bp < end) readSymbolRef(); + owner.newValue(Position.NOPOS, name); + } + if (sym.isModule) { + val clazz = readSymbolRef(); + assert(clazz == sym.moduleClass, sym) + } + syminfo = new LazyTypeRef(inforef, sym); + case _ => + errorBadSignature(""); + } + sym.setFlag(transFlags(pflags)); + sym.setInfo(syminfo); + enterSymbol(sym); + } + } + } + } + sym + } + + def readSymbolRef(): Symbol = getSymbol(readNat()); + + def readSymbolRefs(end: int): List[Symbol] = + if (bp == end) List() + else { + val symref = readNat(); + if (!isSymbolEntry(symref)) List() + else getSymbol(symref) :: readSymbolRefs(end) + } + + def enterSymbol(sym: Symbol): unit = + if (sym.owner.isClass && !sym.isModuleClass) { + if (settings.debug.value) global.log("entering " + sym + ":" + sym.tpe + " in " + sym.owner);//debug + val scope = sym.owner.info.members; + val other = scope.lookup(sym.name); + if (other != sym) { + sym.info match { + case OverloadedType(alts) => alts foreach scope.enter + case _ => scope.enter(sym) + } + } + } + + def getType(i: int, owner: Symbol): Type = { + var tpe = entries(i).asInstanceOf[Type]; + if (tpe == null) { + at(index(i)) { + val tag = readByte(); + val end = readNat() + bp; + tpe = tag match { + case NOtpe => + NoType + case NOpre => + NoPrefix + case THIStpe => + ThisType(readSymbolRef()) + case SINGLEtpe => + singleType(readTypeRef(owner), readSymbolRef()); + case CONSTANTtpe => + ConstantType(readTypeRef(owner), readConstantRef()) + case TYPEREFtpe => + // create a type-ref as found, without checks or rebinds + new ExtTypeRef(readTypeRef(owner), readSymbolRef(), readTypeRefs(end, owner)) + case COMPOUNDtpe => + val isCompoundSym = readByte() != 0; + val ctOwner = if (isCompoundSym) readSymbolRef() else null; + val ctClassRef = readNat(); + val ctClass: Symbol = + if (isCompoundSym) entries(ctClassRef).asInstanceOf[Symbol] + else getSymbol(ctClassRef); + val parents = readTypeRefs(end, owner); + if (ctClass == null) + refinedType(intersectionType(parents), ctOwner) + else if (isCompoundSym) + new ExtRefinedType(intersectionType(parents), new Scope, ctClass) + else + ClassInfoType(parents, new Scope, ctClass); + case METHODtpe => + val restype = readTypeRef(owner); + val argtps = at(bp)(readTypeRefs(end, owner)) map { argtp => + val flags = getFlags(readNat()); + if ((flags & DEFflag) != 0) + PolyType(List(), argtp) + else if ((flags & REPEATEDflag) != 0) + appliedType(definitions.RepeatedParamClass.tpe, List(argtp)) + else + argtp + } + MethodType(argtps, restype) + case POLYtpe => + val restype = readTypeRef(owner); + PolyType(readSymbolRefs(end), restype) + case OVERLOADEDtpe => + val alts = readSymbolRefs(end); + readTypeRefs(end, NoSymbol); + OverloadedType(alts) + case FLAGGEDtpe => + readNat(); // skip flags + readTypeRef(owner) + case _ => + errorBadSignature(""); + } + if (tag != METHODtpe) entries(i) = tpe; + } + } + tpe + } + + def readTypeRef(owner: Symbol): Type = getType(readNat(), owner); + + def readTypeRefs(end: int, owner: Symbol): List[Type] = + if (bp == end) List() + else { + val typeref = readNat(); + if (!isTypeEntry(typeref)) List() + else getType(typeref, owner) :: readTypeRefs(end, owner) + } + + def getFlags(i: int): int = + at(index(i)) { + val tag = readByte(); + val end = readNat() + bp; + if (tag == FLAGGEDtpe) readNat() else 0 + } + + def getConstant(i: int): Any = { + var value = entries(i); + if (value == null) { + at(index(i)) { + val tag = readByte(); + val len = readNat(); + value = tag match { + case LITERALunit => () + case LITERALboolean => if (readByte() == 0) false else true + case LITERALbyte => readLong(len).asInstanceOf[byte] + case LITERALshort => readLong(len).asInstanceOf[short] + case LITERALchar => readLong(len).asInstanceOf[char] + case LITERALint => readLong(len).asInstanceOf[int] + case LITERALlong => readLong(len) + case LITERALfloat => Float.intBitsToFloat(readLong(len).asInstanceOf[int]) + case LITERALdouble => Double.longBitsToDouble(readLong(len)) + case LITERALstring => readNameRef().toString() + case LITERALnull => null + case _ => errorBadSignature("bad constant tag: " + tag) + } + entries(i)= value + } + } + value + } + + def readConstantRef(): Any = getConstant(readNat()); + + def errorBadSignature(msg: String) = + throw new RuntimeException("malformed Scala signature at " + bp + "; " + msg); + + private case class OverloadedType(alts: List[Symbol]) extends Type; + + private class LazyTypeRef(tpref: int, owner: Symbol) extends LazyType { + override def complete(sym: Symbol): unit = + sym.setInfo(getType(tpref, owner)); + } + + private class LazyBoundsTypeRef(hiref: int, loref: int, vubound: boolean) extends LazyType { + override def complete(sym: Symbol): unit = { + val hi = if (vubound) definitions.AnyClass.tpe else getType(hiref, sym); + val vu = if (vubound) getType(hiref, sym) else definitions.AnyClass.tpe; + val lo = getType(loref, sym); + sym.setInfo(TypeBounds(lo, hi, vu)) + } + } + +// --- print symbl files ------------------------------------------------- + + private def tag2string(tag: int): String = tag match { + case TERMname => "TERMname"; + case TYPEname => "TYPEname"; + case NONEsym => "NONEsym"; + case TYPEsym => "TYPEsym"; + case ALIASsym => "ALIASsym"; + case CLASSsym => "CLASSsym"; + case VALsym => "VALsym"; + case EXTref => "EXTref"; + case EXTMODCLASSref => "EXTMODCLASSref"; + case NOtpe => "NOtpe"; + case THIStpe => "THIStpe"; + case SINGLEtpe => "SINGLEtpe"; + case TYPEREFtpe => "TYPEREFtpe"; + case CONSTANTtpe => "CONSTANTtpe"; + case COMPOUNDtpe => "COMPOUNDtpe"; + case METHODtpe => "METHODtpe"; + case POLYtpe => "POLYtpe"; + case OVERLOADEDtpe => "OVERLOADEDtpe"; + case UNBOXEDtpe => "UNBOXEDtpe"; + case UNBOXEDARRAYtpe => "UNBOXEDARRAYtpe"; + case FLAGGEDtpe => "FLAGGEDtpe"; + case ERRORtpe => "ERRORtpe"; + case LITERALunit => "LITERALunit"; + case LITERALboolean => "LITERALboolean"; + case LITERALbyte => "LITERALbyte"; + case LITERALshort => "LITERALshort"; + case LITERALchar => "LITERALchar"; + case LITERALint => "LITERALint"; + case LITERALlong => "LITERALlong"; + case LITERALfloat => "LITERALfloat"; + case LITERALdouble => "LITERALdouble"; + case LITERALstring => "LITERALstring"; + case LITERALnull => "LITERALnull"; + case LITERALzero => "LITERALzero"; + case _ => "***BAD TAG***(" + tag + ")"; + } + + def printAll(out: PrintStream): unit = { + out.println("symbl attribute for " + classRoot + ":"); + for (val i <- Iterator.range(0, index.length)) { + out.print(i + "," + index(i) + ": "); + bp = index(i); + val tag = readByte(); + out.print(tag2string(tag)); + val len = readNat(); + val end = len + bp; + out.print(" " + len); + tag match { + case TERMname | TYPEname => + out.print(" " + UTF8Codec.decode(bytes, bp, len)); + bp = end; + case NONEsym => + case TYPEsym | ALIASsym | CLASSsym | VALsym => + out.print(" " + readNat()); //name + out.print(" " + readNat()); //owner + out.print(" " + Integer.toHexString(readNat())); //flags + out.print(" " + readNat()); //type + case FLAGGEDtpe => + out.print(" " + Integer.toHexString(readNat())); //flags + } + while (bp < end) out.print(" " + readNat()); + out.println(); + } + } + + def transFlags(pflags: int): long = { + var res = 0L; + if ((pflags & Modifiers.DEFERRED ) != 0) res = res | Flags.DEFERRED ; + if ((pflags & Modifiers.FINAL ) != 0) res = res | Flags.FINAL ; + if ((pflags & Modifiers.PRIVATE ) != 0) res = res | Flags.PRIVATE ; + if ((pflags & Modifiers.PROTECTED ) != 0) res = res | Flags.PROTECTED ; + if ((pflags & Modifiers.SEALED ) != 0) res = res | Flags.SEALED ; + if ((pflags & Modifiers.OVERRIDE ) != 0) res = res | Flags.OVERRIDE ; + if ((pflags & Modifiers.CASE ) != 0) res = res | Flags.CASE ; + if ((pflags & Modifiers.ABSTRACT ) != 0) res = res | Flags.ABSTRACT ; + if ((pflags & Modifiers.SYNTHETIC ) != 0) res = res | Flags.SYNTHETIC ; + if ((pflags & Modifiers.DEPRECATED ) != 0) res = res | Flags.DEPRECATED ; + if ((pflags & Modifiers.JAVA ) != 0) res = res | Flags.JAVA ; + if ((pflags & Modifiers.MODUL ) != 0) res = res | Flags.MODULE ; + if ((pflags & Modifiers.MUTABLE ) != 0) res = res | Flags.MUTABLE ; + if ((pflags & Modifiers.PARAM ) != 0) res = res | Flags.PARAM ; + if ((pflags & Modifiers.INITIALIZED ) != 0) res = res | Flags.INITIALIZED; + if ((pflags & Modifiers.LOCKED ) != 0) res = res | Flags.LOCKED ; + if ((pflags & Modifiers.ACCESSED ) != 0) res = res | Flags.ACCESSED ; + if ((pflags & Modifiers.SELECTOR ) != 0) res = res | Flags.SELECTOR ; + if ((pflags & Modifiers.PACKAGE ) != 0) res = res | Flags.PACKAGE ; + if ((pflags & Modifiers.STABLE ) != 0) res = res | Flags.STABLE ; + if ((pflags & Modifiers.CAPTURED ) != 0) res = res | Flags.CAPTURED ; + if ((pflags & Modifiers.INCONSTRUCTOR) != 0) res = res | Flags.INCONSTRUCTOR; + if ((pflags & Modifiers.PARAMACCESSOR) != 0) res = res | Flags.PARAMACCESSOR; + if ((pflags & Modifiers.ACCESSOR ) != 0) res = res | Flags.ACCESSOR ; + if ((pflags & Modifiers.BRIDGE ) != 0) res = res | Flags.BRIDGE ; + if ((pflags & Modifiers.LIFTED ) != 0) res = res | Flags.LIFTED ; + if ((pflags & Modifiers.ALTERNATIVE ) != 0) res = res | Flags.ALTERNATIVE; + if ((pflags & Modifiers.INTERFACE ) != 0) res = res | Flags.TRAIT ; + if ((pflags & Modifiers.TRAIT ) != 0) res = res | Flags.TRAIT ; + if ((pflags & Modifiers.COVARIANT ) != 0) res = res | Flags.COVARIANT ; + if ((pflags & Modifiers.CONTRAVARIANT) != 0) res = res | Flags.CONTRAVARIANT; + res + } +} +} +*/ diff --git a/sources/scala/tools/nsc/typechecker/Analyzer.scala b/sources/scala/tools/nsc/typechecker/Analyzer.scala new file mode 100644 index 0000000000..6c48cff25f --- /dev/null +++ b/sources/scala/tools/nsc/typechecker/Analyzer.scala @@ -0,0 +1,3020 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +// todo: eliminate Typed nodes. +// todo: use SELECTOR flag to avoid access methods for privates +// todo: use mangled name or drop. +// todo: emit warnings for unchecked. +// todo: synchronize on module instantiation. +// todo: empty package + +import ch.epfl.lamp.util.Pair; +import scala.tools.util.Position; +import scalac._; +import scalac.util._; +import scalac.ast._; +import scalac.atree.AConstant; +import scalac.atree.AConstant$CHAR; +import scalac.atree.AConstant$INT; +import scalac.symtab.classfile._; +import scalac.symtab._; +import Tree._; +import java.util.HashMap; +import scala.tools.scalac.util.NewArray; +import scalac.{Global => scalac_Global} + +package scala.tools.scalac.typechecker { + +import java.lang.{Boolean, Byte, Short, Character, Integer, Object} + +/** The main attribution phase. + */ +class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(global) { + + import Modifiers._; + import Kinds._; + + private var context: Context = _; + private var pt: Type = _; + private var mode: int = _; + + private var inAlternative: boolean = _; + private val patternVars = new HashMap(); // for pattern matching; maps x to {true,false} + + val definitions = global.definitions; + val infer = new scala.tools.scalac.typechecker.Infer(this) { + override def getContext = context; + override def error(pos: int, msg: String) = Analyzer.this.error(pos, msg); + } + val desugarize = new DeSugarize(make, copy, gen, infer, global); + val constfold = new ConstantFolder(global); + + var unit: CompilationUnit = _; + + type AttrInfo = Pair/*<Symbol, Array[AConstant]>*/ ; + + def enterUnit(unit: CompilationUnit): unit = + enter( + new Context( + Tree.Empty, + if (unit.console) descr.consoleContext else descr.startContext), + unit); + + def enter(context: Context, unit: CompilationUnit): unit = { + assert(this.unit == null, "start unit non null for " + unit); + context.infer = infer; + this.unit = unit; + this.context = context; + descr.contexts.put(unit, context); + enterSyms(unit.body); + this.unit = null; + this.context = null; + } + + def lateEnter(unit: CompilationUnit): unit = { + enterUnit(unit); + } + + def loadMixinCode(pos: Int, clasz: Symbol): unit = { + assert(clasz.isClass() && !clasz.isModuleClass(), Debug.show(clasz)); + if (clasz.isExternal()) { + var c: Symbol = clasz; + try { + while (!c.owner().isPackageClass()) c = c.owner(); + global.compileLate(global.getSourceFile(c), true); + } catch { + case exception: java.io.IOException => + if (global.debug) exception.printStackTrace(); + unit.error(pos, exception.getMessage() + "; source file for " + + c + " is needed because it is used as a mixin"); + } + } + } + + override def apply(unit: CompilationUnit): unit = { + global.log("checking " + unit); + assert(this.unit == null, "start unit non null for " + unit); + this.unit = unit; + this.context = descr.contexts.remove(unit).asInstanceOf[Context]; + assert(this.context != null, "could not find context for " + unit); + unit.body = transformStatSeq(unit.body, Symbol.NONE); + if (global.target != scalac_Global.TARGET_INT && global.reporter.errors() == 0) { + genSymData(unit.body); + } + this.unit = null; + this.context = null; + global.operation("checked " + unit); + } + + def genSymData(stats: Array[Tree]): unit = { + var i = 0; while (i < stats.length) { + stats(i) match { + case Tree.ClassDef(_, _, _, _, _, _) | Tree.ModuleDef(_, _, _, _) => + val sym = stats(i).symbol(); + val key = if (sym.isModule()) sym.moduleClass() else sym; + var termSym = sym.owner().info().lookup(sym.name.toTermName()); + var typeSym = sym.owner().info().lookup(sym.name.toTypeName()); + if (termSym.isExternal()) termSym = Symbol.NONE; + if (typeSym.isExternal()) typeSym = Symbol.NONE; + if (sym.isClass() || (sym.isModule() && typeSym.isNone())) { + val pickle: Pickle = new Pickle(); + if (!termSym.isNone()) pickle.add(termSym); + if (!typeSym.isNone()) pickle.add(typeSym); + pickle.pickle(); + global.symdata.put(key, pickle); + } + case Tree.PackageDef(packaged, templ) => + genSymData(templ.body); + case _ => + } + i = i + 1 + } + } + + /** Mode constants + */ + val NOmode = 0x000; + val EXPRmode = 0x001; // these 4 modes are mutually exclusive. + val PATTERNmode = 0x002; + val CONSTRmode = 0x004; + val TYPEmode = 0x008; + + val FUNmode = 0x10; // orthogonal to above. When set + // we are looking for a method or constructor + + val POLYmode = 0x020; // orthogonal to above. When set + // expression types can be polymorphic. + + val QUALmode = 0x040; // orthogonal to above. When set + // expressions may be packages and + // Java statics modules. + + val SUPERmode = 0x080; // Goes with CONSTRmode. When set + // we are checking a superclass + // constructor invocation. + + val baseModes = EXPRmode | PATTERNmode | CONSTRmode; + + val SEQUENCEmode = 0x1000; // orthogonal to above. When set + // we turn "x" into "x@_" + // and allow args to be of type Seq( a) instead of a + +// Diagnostics ---------------------------------------------------------------- + + private def errorName(tree: Tree): Name = + Name.fromString("<error: " + tree + ">"); + + private def errorTree(tree: Tree): Tree = + try { + if (tree.isType()) errorTypeTree(tree) else errorTermTree(tree); + } catch { + case ex: Type$Error => + Tree.Empty; + } + + private def errorTypeTree(tree: Tree): Tree = { + val symbol = context.owner.newErrorClass(errorName(tree).toTypeName()); + tree match { + case Tree.Ident(_) => + make.Ident(tree.pos, symbol).setType(symbol.getType()); + case Tree.Select(qualifier, _) => + make.Select(tree.pos, symbol, qualifier).setType(symbol.getType()); + case _ => + gen.mkType(tree.pos, symbol.getType()); + } + } + + private def errorTermTree(tree: Tree): Tree = + gen.mkLocalRef(tree.pos, Symbol.NONE.newErrorValue(errorName(tree))); + + private def setError(tree: Tree): Tree = { + if (tree.hasSymbol() && tree.symbol() == null) + tree.setSymbol( + if (tree.isType()) Symbol.NONE.newErrorClass(errorName(tree).toTypeName()) + else Symbol.NONE.newErrorValue(errorName(tree))); + tree.setType(Type.ErrorType); + } + + def error(pos: int, msg: String): unit = + unit.error(pos, msg); + + def typeError(pos: int, found: Type, req: Type): unit = { + if (found.isError() || req.isError()) return; + var msg: String = infer.typeErrorMsg("type mismatch", found, req); + val foundResult: Type = found.resultType(); + if (foundResult != found && infer.isCompatible(foundResult, req)) + msg = msg + "\n possible cause: missing arguments for method or constructor"; + error(pos, msg); + } + + def reportTypeError(pos: int, ex: Type$Error): unit = { + if (global.debug) ex.printStackTrace(); + if (ex.isInstanceOf[CyclicReference]) { + val cyc: CyclicReference = ex.asInstanceOf[CyclicReference]; + if (cyc.info.isInstanceOf[LazyTreeType]) { + (cyc.info.asInstanceOf[LazyTreeType]).tree match { + case Tree.ValDef(_, _, Tree.Empty, _) => + return error(pos, "recursive " + cyc.sym + " needs type"); + case Tree.DefDef(_, _, _, _, Tree.Empty, _) => + return error(pos, "recursive function " + cyc.sym.name + " needs result type"); + case _ => + } + } + } + error(pos, ex.msg); + } + + def decode(name: Name): String = + if (name.isTypeName()) "type " + NameTransformer.decode(name); + else "value " + NameTransformer.decode(name); + +// Checking methods ---------------------------------------------------------- + + /** Check that symbol's definition is well-formed. This means: + * - no conflicting modifiers + * - `abstract' modifier only for classes + * - `override' modifier never for classes + * - `def' modifier never for parameters of case classes + * - declarations only in traits or abstract classes + * - symbols with `override' modifier override some other symbol. + */ + def validate(sym: Symbol): unit = { + if ((sym.flags & (ABSTRACT | OVERRIDE)) == ABSTRACT && sym.kind != CLASS) { + error(sym.pos, "`abstract' modifier can be used only for classes; " + + "\nit should be omitted for abstract members"); + } + if ((sym.flags & OVERRIDE) != 0 && sym.kind == CLASS) { + error(sym.pos, "`override' modifier not allowed for classes"); + } + if ((sym.flags & DEF) != 0 && sym.owner().isPrimaryConstructor() && + (sym.owner().constructorClass().flags & CASE) != 0) { + error(sym.pos, "pass-by-name arguments not allowed for case class parameters"); + } + /*!!! + if ((sym.flags & REPEATED) != 0 && sym.owner().isPrimaryConstructor()) { + error(sym.pos, "`*' modifier not allowed for class parameters"); + } + */ + if ((sym.flags & DEFERRED) != 0) { + if (sym.owner().kind != CLASS || (sym.owner().flags & MODUL) != 0 || sym.owner().isAnonymousClass()) { + error(sym.pos, + "only classes can have declared but undefined members" + + (if ((sym.flags & MUTABLE) == 0) "" + else "\n(Note that variables need to be initialized to be defined)")); + sym.flags = sym.flags & ~DEFERRED; + } + } + checkNoConflict(sym, DEFERRED, PRIVATE); + checkNoConflict(sym, FINAL, SEALED); + if ((sym.flags & MODUL) == 0) checkNoConflict(sym, FINAL, PRIVATE); + checkNoConflict(sym, PRIVATE, PROTECTED); + checkNoConflict(sym, PRIVATE, OVERRIDE); + checkNoConflict(sym, DEFERRED, FINAL); + } + + /** Check that + * - all parents are class types + * - supertype conforms to supertypes of all mixin types. + * - final classes are only inherited by classes which are + * nested within definition of base class, or that occur within same + * statement sequence. + * - self-type of current class is a subtype of self-type of each parent class. + * - parent constructors do not refer to value parameters of class. + * - no two parents define same symbol. + */ + def validateParentClasses(constrs: Array[Tree], parents: Array[Type], selfType: Type): unit = { + var i = 0; + while (i < parents.length) { + if (!checkClassType(constrs(i).pos, parents(i))) return; + val bsym: Symbol = parents(i).symbol(); + if (i > 0) { + if ((bsym.flags & (JAVA | INTERFACE)) == JAVA) + error(constrs(i).pos, "Java class may not be used as mixin"); + val grandparents = parents(i).parents(); + if (grandparents.length > 0 && !parents(0).isSubType(grandparents(0))) + error(constrs(i).pos, "illegal inheritance;\n " + parents(0) + + " does not conform to " + parents(i) + "'s supertype " + grandparents(0)); + } + if ((bsym.flags & FINAL) != 0) { + error(constrs(i).pos, "illegal inheritance from final class"); + } else if (bsym.isSealed() || + bsym.isSubClass(definitions.ANYVAL_CLASS) || + bsym.isSubClass(definitions.ARRAY_CLASS)) { + // are we in same scope as base type definition? + val e: Scope$Entry = context.scope.lookupEntry(bsym.name); + if (e.sym != bsym) { + // we are not within same statement sequence + var c: Context = context; + while (c != Context.NONE && c.owner != bsym) + c = c.outer.enclClass; + if (c == Context.NONE) { + error(constrs(i).pos, "illegal inheritance from sealed class"); + } + } + } + if (!selfType.isSubType(parents(i).instanceType())) { + error(constrs(i).pos, "illegal inheritance;\n self-type " + + selfType + " does not conform to " + parents(i) + + "'s selftype " + parents(i).instanceType()); + } + var j = 0; while (j < i) { + if (parents(i).symbol() == parents(j).symbol()) + error(constrs(i).pos, "" + parents(i).symbol() + " is inherited twice"); + j = j + 1 + } + i = i + 1; + } + } + + /** Check that type is a class type. + */ + private def checkClassType(pos: int, tp: Type): boolean = { + tp.unalias() match { + case Type$TypeRef(_, sym, _) => + if (sym.kind == CLASS) return true; + case _ => + } + if (!tp.isError()) error(pos, "class type expected"); + false + } + + /** Check that type is an object type + */ + private def checkObjectType(pos: int, tp: Type): Type = + if (tp.isObjectType()) tp + else { + if (!tp.isError()) error(pos, "object type expected"); + Type.ErrorType + } + + /** Check that type is eta-expandable (i.e. no `def' or `*' parameters) + */ + def checkEtaExpandable(pos: int, tp: Type): unit = tp match { + case Type$MethodType(params, restype) => + var i = 0; while (i < params.length) { + if ((params(i).flags & DEF) != 0) + error(pos, "method with pass-by-name parameters needs to be fully applied"); + if ((params(i).flags & REPEATED) != 0) + error(pos, "method with `*' parameters needs to be fully applied"); + i = i + 1 + } + checkEtaExpandable(pos, restype); + case _ => + } + + /** Check that `sym' does not contain both `flag1' and `flag2' + */ + def checkNoConflict(sym: Symbol, flag1: int, flag2: int): unit = { + if ((sym.flags & (flag1 | flag2)) == (flag1 | flag2)) { + if (flag1 == DEFERRED) + error(sym.pos, "abstract member may not have " + + Modifiers$Helper.toString(flag2) + " modifier"); + else + error(sym.pos, "illegal combination of modifiers: " + + Modifiers$Helper.toString(flag1) + " and " + + Modifiers$Helper.toString(flag2)); + } + } + + /** Check that type `tp' is not a subtype of itself. + */ + def checkNonCyclic(pos: int, tp: Type): unit = tp match { + case Type$TypeRef(pre, sym, args) => + sym.initialize(); + if ((sym.flags & LOCKED) != 0) { + error(pos, "cyclic aliasing or subtyping involving " + sym); + } else if (sym.kind == ALIAS || sym.kind == TYPE) { + sym.flags = sym.flags | LOCKED; + //System.out.println("checking " + sym);//DEBUG + checkNonCyclic( + pos, pre.memberInfo(sym).subst(sym.typeParams(), args)); + if (sym.kind == TYPE) { + checkNonCyclic( + pos, pre.memberLoBound(sym).subst(sym.typeParams(), args)); + checkNonCyclic( + pos, pre.memberVuBound(sym).subst(sym.typeParams(), args)); + } + sym.flags = sym.flags & ~LOCKED; + } + + case Type$CompoundType(parents, members) => + var i = 0; while (i < parents.length) { + checkNonCyclic(pos, parents(i)); + i = i + 1 + } + + case Type$SingleType(pre, sym) => + sym.initialize(); + if ((sym.flags & LOCKED) != 0) { + error(pos, "cyclic aliasing or subtyping involving " + sym); + } + + case _ => + } + + /** Check that type does not refer to components defined in current scope. + */ + def checkNoEscape(pos: int, tp: Type): Type = { + + val checkNoEscapeMap = new Type$Map() { + override def apply(t: Type): Type = { + t.unalias() match { + case Type$TypeRef(Type.NoPrefix, sym, args) => + checkNoEscape(t, sym); + case Type$SingleType(Type.NoPrefix, sym) => + checkNoEscape(t, sym); + case _ => + } + return map(t); + } + private def checkNoEscape(t: Type, sym: Symbol): unit = { + val e: Scope$Entry = context.scope.lookupEntry(sym.name); + if (e.sym == sym && e.owner == context.scope && + !(e.sym.kind == TYPE && (e.sym.flags & PARAM) != 0)) { + throw new Type$Error( + "type " + t + " escapes its defining scope"); + } + } + }; + + try { + checkNoEscapeMap.apply(tp) + } catch { + case ex: Type$Error => + if ((mode & EXPRmode) != 0 && infer.isFullyDefined(pt)) pt + else { + error(pos, ex.msg + " as part of " + tp.unalias()); + Type.ErrorType + } + } + } + + /** Check that there are no dependent parameter types among parameters + */ + def checkNoEscapeParams(vparams: Array[Array[Tree.ValDef]]): unit = { + var i = 0; while (i < vparams.length) { + var j = 0; while (j < vparams(i).length) { + checkNoEscape(vparams(i)(j).pos, vparams(i)(j).tpe.getType()); + j = j + 1 + } + i = i + 1 + } + } + + /** Check that tree represents a legal trait definition. + */ + def checkTraitDef(pos: int, clazz: Symbol, templ: Tree.Template) = { + + /** Check that type does not have value parameters + */ + def checkNoParams(tpe: Type): unit = tpe match { + case Type$MethodType(vparams, _) => + if (vparams.length > 0) + error(pos, "trait may not have value parameters") + case Type$PolyType(tparams, restpe) => + checkNoParams(infer.skipViewParams(tparams, restpe)) + case _ => + } + + /** Check that tree represents a pure constructor. + */ + def checkPureConstr(tree: Tree): unit = { + if (!TreeInfo.isPureConstr(tree) && !tree.getType().isError()) + error(tree.pos, "" + clazz + " may invoke only pure superclass constructors"); + } + + /** Check that tree refers to a trait + */ + def checkTraitRef(tree: Tree): unit = { + if (!tree.getType().symbol().isTrait() && !tree.getType().isError()) + error(tree.pos, " " + clazz + " may inherit only traits as mixins"); + } + + /** Check that tree represents a pure definition. + */ + def checkPureDef(tree: Tree): unit = { + if (!TreeInfo.isPureDef(tree) && !tree.getType().isError()) + error(tree.pos, "" + clazz + " may contain only pure definitions"); + } + + checkNoParams(clazz.primaryConstructor().getType()); + var i = 0; while (i < templ.parents.length) { + checkPureConstr(templ.parents(i)); + if (i >= 1) checkTraitRef(templ.parents(i)); + i = i + 1 + } + var j = 0; while (j < templ.body.length) { + checkPureDef(templ.body(j)); + j = j + 1 + } + } + + /** Check that tree is a stable expression .p + */ + def checkStable(tree: Tree): Tree = + if (TreeInfo.isPureExpr(tree) || tree.getType().isError()) tree; + else { + error(tree.pos, "stable identifier required, but " + tree + " found."); + errorTermTree(tree); + } + + /** Check that class can be instantiated. + */ + def checkInstantiatable(pos: int, tp: Type): unit = { + val clazz: Symbol = tp.symbol(); + if (clazz.kind == CLASS) { + if (clazz.isAbstractClass()) + error(pos, "" + clazz + " is abstract, so it cannot be instantiated"); + else if (!tp.isSubType(tp.instanceType())) + error(pos, "" + tp + " does not conform to its self-type " + + tp.instanceType() + ", so it cannot be instantiated"); + } + } + + /** Check that all subtrees have their types defined. + * Used for asserting an internal invariant + */ + private class CheckDefined extends Traverser { + var all: Tree = null; + override def traverse(tree: Tree): unit = { + if (tree.getType() == null) assert(false, "" + tree + " in " + all); + if (!tree.getType().isError()) + super.traverse(tree); + } + } + + private val checkDefined: CheckDefined = new CheckDefined(); + + // Helper definitions for calculating types ----------------------------------------- + + /** The qualifier type of a potential application of the `match' method. + * or NoType, if this is something else. + */ + private def matchQualType(fn: Tree): Type = { + fn match { + case Tree.Select(qual, _) => + if (fn.symbol() == definitions.ANY_MATCH) + return qual.getType().widen(); + + case Tree.TypeApply(fn1, _) => + return matchQualType(fn1); + + case Tree.Ident(_) => + if (fn.symbol() == definitions.ANY_MATCH) + return context.enclClass.owner.typeOfThis(); + + case _ => + } + if (fn.getType().isError()) Type.ErrorType else Type.NoType + } + + private def isSetterMethod(sym: Symbol): boolean = + sym != null && + !sym.isLocal() && + !sym.isStable() && + sym.getType().isInstanceOf[Type$PolyType] && + sym.typeParams().length == 0; + +// Views ----------------------------------------------------------------------- + + private def applyView(v: View, tree: Tree, mode: int, pt: Type): Tree = { + val vexpr = infer.viewExpr(tree.pos, v); + val vapp = transform( + make.Apply(tree.pos, vexpr, NewArray.Tree(tree)), mode, pt); + if (v.symtype.isObjectType()) { + val tree1 = gen.mkAsInstanceOf(tree.duplicate(), vapp.getType()); + gen.If( + gen.Apply( + gen.Select( + vexpr.duplicate(), + definitions.ANY_EQEQ), + NewArray.Tree(gen.mkNullLit(tree.pos))), + tree1, + vapp) + } else vapp + } + +// Contexts ------------------------------------------------------------------- + + /** Push new context associated with given tree, owner, and scope on stack. + */ + def pushContext(tree: Tree, owner: Symbol, scope: Scope): Context = { + val prevContext = context; + context = new Context(tree, owner, scope, context); + prevContext + } + +// Lazy Types ------------------------------------------------------------------ + + /** A lazy type which, when forced returns the type of a symbol defined + * in `tree'. + */ + class LazyTreeType(_tree: Tree) extends Type$LazyType { + val tree: Tree = _tree; + val u: CompilationUnit = unit; + val c: Context = context; + + override def complete(sym: Symbol): unit = { + defineSym(tree, u, c); + } + } + + /** A lazy type for case constructor methods (whose name is a term name) + * which sets the method's type to the class constructor type. + */ + class LazyConstrMethodType(_tree: Tree) extends LazyTreeType(_tree) { + override def complete(sym: Symbol): unit = { + val constr: Symbol = tree.symbol().primaryConstructor(); + if (!sym.isInitialized()) + sym.setInfo(constr.getType().instanceType().cloneType(constr, sym)); + } + } + + /** A lazy type for self types + */ + class LazySelfType(clazz: Symbol, tree: Tree) extends LazyTreeType(tree) { + override def complete(sym: Symbol): unit = { + defineSelfType(sym, clazz, tree, u, c); + } + } + +// Entering Symbols ---------------------------------------------------------- + + def transformPackageId(tree: Tree): Tree = { + if (tree.getType() != null) return tree; + tree match { + case Tree.Ident(name) => + tree + .setSymbol(packageSymbol(tree.pos, context.owner, name)) + .setType(tree.symbol().getType()) + + case Tree.Select(qual, name) => + val qual1: Tree = transformPackageId(qual); + val sym: Symbol = packageSymbol(tree.pos, qual1.symbol().moduleClass(), name); + copy.Select(tree, sym, qual1).setType(sym.getType()) + + case _ => + transform(tree); + } + } + + def packageSymbol(pos: int, base: Symbol, name: Name): Symbol = { + var p: Symbol = base.members().lookup(name); + if (p.isNone()) { + p = base.newPackage(pos, name); + base.members().enterNoHide(p); + } else if (p.isPackage()) { + // as the package is used, we change its position to make sure + // its symbol is not reused for a module definition with the + // same name + p.pos = Position.FIRSTPOS; + p.moduleClass().pos = Position.FIRSTPOS; + } else { + val dst = if ((p.flags & CASE) != 0) "case class " + name; + else "" + p; + error(pos, "package " + name + " has the same name as existing " + dst); + p = base.newPackage(pos, name); + } + p + } + + def moduleSymbol(pos: int, name: Name, owner: Symbol, flags: int, scope: Scope): Symbol = { + val symbol = termSymbolOrNone(scope, pos, name, flags | MODUL | FINAL); + if (symbol.isNone()) owner.newModule(pos, flags, name) else symbol; + } + + def termSymbol(pos: int, name: Name, owner: Symbol, flags: int, scope: Scope): Symbol = { + val symbol = termSymbolOrNone(scope, pos, name, flags); + if (symbol.isNone()) owner.newTerm(pos, flags, name) else symbol + } + + def classSymbol(pos: int, name: Name, owner: Symbol, flags: int, scope: Scope): Symbol = { + val symbol = typeSymbolOrNone(scope, pos, CLASS, name, flags); + if (symbol.isNone()) owner.newClass(pos, flags, name) else symbol + } + + def typeAliasSymbol(pos: int, name: Name, owner: Symbol, flags: int, scope: Scope): Symbol = { + val symbol = typeSymbolOrNone(scope, pos, ALIAS, name, flags); + if (symbol.isNone()) owner.newTypeAlias(pos, flags, name) else symbol + } + + def absTypeSymbol(pos: int, name: Name, owner: Symbol, flags: int, scope: Scope): Symbol = { + val symbol = typeSymbolOrNone(scope, pos, TYPE, name, flags); + if (symbol.isNone()) owner.newAbstractType(pos, flags, name) else symbol + } + + def termSymbolOrNone(scope: Scope, pos: int, name: Name, flags: int): Symbol = { + var symbol = getDefinedSymbol(scope, VAL, name); + if (!symbol.isNone()) { + if (symbol.isInitialized()) { + symbol.getType() match { + case Type$OverloadedType(alts, _) => + var i = 0; + while (i < alts.length && !alts(i).isExternal()) i = i + 1; + if (i == alts.length) + throw Debug.abort("missing alternative", Debug.show(symbol)); + if (i == alts.length - 1) symbol.pos = pos; + symbol = alts(i); + case _ => + } + } + updateFlagsAndPos(symbol, pos, flags); + } + symbol + } + + def typeSymbolOrNone(scope: Scope, pos: int, kind: int, name: Name, flags: int): Symbol = { + val symbol = getDefinedSymbol(scope, kind, name); + if (!symbol.isNone()) { + updateFlagsAndPos(symbol, pos, flags); + symbol.allConstructors().pos = pos; + } + symbol + } + + def getDefinedSymbol(scope: Scope, kind: int, name: Name): Symbol = { + val entry = scope.lookupEntry(name); + val symbol = entry.sym; + if (entry.owner == scope && symbol.isExternal() && symbol.kind == kind) { + symbol + } else { + Symbol.NONE; + } + } + + def updateFlagsAndPos(symbol: Symbol, pos: int, flags: int): unit = { + symbol.pos = pos; + val oldflags = symbol.flags & (INITIALIZED | LOCKED); + val newflags = flags & ~(INITIALIZED | LOCKED); + symbol.flags = oldflags | newflags; + if (symbol.isModule()) { + // here we repeat what is done in the constructor of ModuleClassSymbol + val clasz = symbol.moduleClass(); + val classFlags = (flags & MODULE2CLASSFLAGS) | MODUL | FINAL; + updateFlagsAndPos(clasz, pos, classFlags); + clasz.primaryConstructor().flags = + clasz.primaryConstructor().flags | PRIVATE; + } + if (symbol.isType()) { + // here we repeat what is done in the constructor of TypeSymbol + val constr = symbol.primaryConstructor(); + val constrFlags = flags & CONSTRFLAGS; + updateFlagsAndPos(constr, pos, constrFlags); + } + } + + /** Enter symbol `sym' in current scope. Check for double definitions. + * Handle overloading. + */ + def enterInScope(sym: Symbol): unit = { + + def covers(presym: Symbol, newsym: Symbol) = { + if (presym == newsym) true + else if (!presym.isInitialized()) false + else presym.getType() match { + case Type$OverloadedType(alts, _) => + var i = 0; + while (i < alts.length && alts(i) != newsym) i = i + 1; + i < alts.length + case _ => + false + } + } + + // handle double and overloaded definitions + val e: Scope$Entry = context.scope.lookupEntry(sym.name); + val other: Symbol = e.sym; + if (covers(other, sym)) { + if (global.debug) global.log("redefined: " + sym + ":" + sym.rawInfo()); + } else if (e.owner == context.scope) { + assert(!other.isExternal(), other); + if (sym.owner().isPackageClass()) { + if (other.isPackage()) { + val src = if ((sym.flags & CASE) != 0) "case class " + sym.name; + else "" + sym; + error(sym.pos, "" + src + " has the same name as existing " + other); + } else { + if (global.compiledNow.get(other) != null) { + error(sym.pos, "" + sym + " is compiled twice"); + } + context.scope.unlink(e); + context.scope.enter(sym); + } + } else if (context.owner.kind == CLASS && + sym.kind == VAL && other.kind == VAL && + ((sym.flags & ACCESSOR) == 0 || (other.flags & ACCESSOR) == 0) + || + (sym.name == Names.view && + (sym.flags & (PARAM | SYNTHETIC)) == (PARAM | SYNTHETIC))) { + e.setSymbol(other.overloadWith(sym)); + } else if (context.owner.kind == CLASS) + error(sym.pos, + sym.nameString() + " is already defined as " + + other + other.locationString()); + else + error(sym.pos, + sym.nameString() + + " is already defined in local scope"); + } else { + context.scope.enter(sym); + } + if (sym.owner().isPackageClass()) + global.compiledNow.put(sym, unit.source); + } + + def outerEnterSym(tree: Tree): Symbol = enterSym(tree); + + /** If `tree' is a definition, create a symbol for it with a lazily + * constructed type, and enter into current scope. + */ + def enterSym(tree: Tree): Symbol = { + + /** Enter `sym' in current scope and make it the symbol of `tree'. + */ + def enterSym(tree: Tree, sym: Symbol): Symbol = { + //if (global.debug) System.out.println("entering " + sym);//DEBUG + if (!sym.isInitialized()) { + sym.setInfo(new LazyTreeType(tree)); + } + if (!sym.isConstructor()) { + val owner: Symbol = sym.owner(); + if (sym.kind == VAL && (sym.flags & (PRIVATE | SEALED)) == 0 && + owner != null && owner.kind == CLASS && + (owner.flags & FINAL) != 0) + sym.flags = sym.flags | FINAL; + enterInScope(sym); + } + tree.setSymbol(sym); + sym + } + + /** Make `sym' the symbol of import `tree' and push an + * import context. + */ + def enterImport(tree: Tree, sym: Symbol): Symbol = { + sym.setInfo(new LazyTreeType(tree)); + tree.setSymbol(sym); + pushContext(tree, context.owner, context.scope); + sym + } + + val owner: Symbol = context.owner; + tree match { + case Tree.PackageDef(_packaged, templ) => + var packaged = _packaged; + templ match { + case Tree.Template(_, body) => + val prevContext = pushContext(tree, context.owner, context.scope); + packaged = transformPackageId(packaged); + tree.asInstanceOf[Tree.PackageDef].packaged = packaged; + context = prevContext; + val pkg: Symbol = checkStable(packaged).symbol(); + if (pkg != null && !pkg.isError()) { + if (pkg.isPackage()) { + val prevContext = pushContext(templ, pkg.moduleClass(), pkg.members()); + enterSyms(body); + context = prevContext; + } else { + error(tree.pos, "only Java packages allowed for now"); + } + } + templ.setSymbol(Symbol.NONE); + null + case _ => + throw new ApplicationError(); + } + + case Tree.Attributed(attr, definition) => + outerEnterSym(definition); + + case Tree.DocDef(comment, definition) => + val sym = outerEnterSym(definition); + global.mapSymbolComment.put(sym, new Pair(comment, unit)); + sym + + case Tree.ClassDef(mods, name, tparams, vparams, _, templ) => + val clazz = + if (mods == SYNTHETIC && name == Names.ANON_CLASS_NAME.toTypeName()) + context.owner.newAnonymousClass(templ.pos, name) + else + classSymbol(tree.pos, name, owner, mods, context.scope); + if (!clazz.primaryConstructor().isInitialized()) + clazz.primaryConstructor().setInfo(new LazyTreeType(tree)); + if ((mods & CASE) != 0) { + if ((mods & ABSTRACT) == 0) { + // enter case constructor method. + val cf: Symbol = termSymbol( + tree.pos, name.toTermName(), owner, + mods & ACCESSFLAGS | CASE, context.scope); + enterInScope(cf); + if (!cf.isInitialized() || cf.info().symbol().isModuleClass()) { + cf.setInfo(new LazyConstrMethodType(tree)); + } + } + } + enterSym(tree, clazz) + + case Tree.ModuleDef(mods, name, _, _) => + var modul = moduleSymbol(tree.pos, name, owner, mods, context.scope); + val clazz: Symbol = modul.moduleClass(); + if (!clazz.isInitialized()) { + val info = new LazyTreeType(tree); + clazz.setInfo(info); + modul.setInfo(info); + } + enterSym(tree, modul) + + case Tree.ValDef(mods, name, _, _) => + enterSym(tree, termSymbol(tree.pos, name, owner, mods, context.scope)) + + case Tree.DefDef(mods, name, _, _, _, _) => + var sym: Symbol = null; + if (name == Names.CONSTRUCTOR) { + var c = context; + while (c.isImportContext) c = c.outer; + val clazz: Symbol = c.enclClass.owner; + if (!(c.tree.isInstanceOf[Tree.Template]) || + clazz.isModuleClass() || + clazz.isAnonymousClass() || + clazz.isCompoundSym() || + clazz.isPackageClass()) + error(tree.pos, "constructor definition not allowed here"); + sym = clazz.newConstructor(tree.pos, clazz.flags & CONSTRFLAGS); + clazz.addConstructor(sym); + sym.flags = sym.flags | mods; + } else { + sym = termSymbol(tree.pos, name, owner, mods, context.scope); + } + enterSym(tree, sym); + + case Tree.AliasTypeDef(mods, name, _, _) => + val tsym: Symbol = typeAliasSymbol(tree.pos, name, owner, mods, context.scope); + if (!tsym.primaryConstructor().isInitialized()) + tsym.primaryConstructor().setInfo(new LazyTreeType(tree)); + enterSym(tree, tsym) + + case Tree.AbsTypeDef(mods, name, _, _) => + enterSym( + tree, + absTypeSymbol(tree.pos, name, owner, mods, context.scope)) + + case Tree.Import(expr, selectors) => + enterImport(tree, + Symbol.NONE.newTerm( + tree.pos, SYNTHETIC, Name.fromString("import " + expr))) + + case _ => + null + } + } + + /** Enter all symbols in statement list + */ + def enterSyms(stats: Array[Tree]): unit = { + var i = 0; while (i < stats.length) { + stats(i) = desugarize.Definition(stats(i)); + enterSym(stats(i)); + i = i + 1 + } + } + + def enterParams[t <: Tree](params: Array[t]): Array[Symbol] = { + var i = 0; while (i < params.length) { + enterSym(params(i)); + (params(i) : Tree) match { + case Tree.ValDef(mods, _, _, _) => + if ((mods & REPEATED) != 0 && i != params.length - 1) + error(params(i).pos, + "`*' parameter must be the last parameter of a `('...`)' section"); + case _ => + } + i = i + 1 + } + Tree.symbolOf(params.asInstanceOf[Array[Tree]]) + } + + def enterParams(vparams: Array[Array[Tree.ValDef]]): Array[Array[Symbol]] = { + val vparamSyms = new Array[Array[Symbol]](vparams.length); + var i = 0; while (i < vparams.length) { + vparamSyms(i) = enterParams(vparams(i)); + i = i + 1 + } + vparamSyms + } + + /** Re-enter type parameters in current scope. + */ + def reenterParams(tparams: Array[Tree.AbsTypeDef], tsyms: Array[Symbol]): unit = { + var i = 0; while (i < tparams.length) { + tsyms(i).pos = tparams(i).pos; + tsyms(i).name = tparams(i).name; + //necessary since tsyms might have been unpickled + tparams(i).setSymbol(tsyms(i)); + context.scope.enter(tsyms(i)); + i = i + 1 + } + } + + /** Re-enter type and value parameters in current scope. + */ + def reenterParams(tparams: Array[Tree.AbsTypeDef], vparamss: Array[Array[Tree.ValDef]], mt: Type): unit = { + var rest: Type = mt; + rest match { + case Type$PolyType(tsyms, restp) => + reenterParams(tparams, tsyms); + rest = restp; + case _ => + } + var j = 0; while (j < vparamss.length) { + val vparams = vparamss(j); + rest match { + case Type$MethodType(vsyms, restp) => + var i = 0; while (i < vparams.length) { + vsyms(i).pos = vparams(i).pos; + vsyms(i).name = vparams(i).name; + //necessary since vsyms might have been unpickled + vparams(i).setSymbol(vsyms(i)); + //potential overload in case this is a view parameter + context.scope.enterOrOverload(vsyms(i)); + i = i + 1 + } + rest = restp; + case _ => + } + j = j + 1 + } + } + + def addInheritedOverloaded(sym: Symbol, tp: Type): unit = + if (sym.owner().kind == CLASS && + !sym.isConstructor() && + sym.owner().lookup(sym.name) == sym) + // it's a class member which is not an overloaded alternative + sym.addInheritedOverloaded(tp); + +// Definining Symbols ------------------------------------------------------- + + /** Define symbol associated with `tree' using given `unit' and `context'. + */ + def defineSym(tree: Tree, unit: CompilationUnit, curcontext: Context): unit = { + val savedUnit: CompilationUnit = this.unit; + this.unit = unit; + val savedContext: Context = this.context; + this.context = curcontext; + val savedMode: int = this.mode; + this.mode = EXPRmode; + val savedPt: Type = this.pt; + this.pt = Type.AnyType; + + try { + val sym: Symbol = tree.symbol(); + if (global.debug) global.log("defining " + sym); + var owntype: Type = null; + tree match { + case Tree.ClassDef(mods, name, tparams, vparams, tpe, templ) => + val prevContext = pushContext( + tree, sym.primaryConstructor(), new Scope(context.scope)); + val tparamSyms = enterParams(tparams); + var vparamSyms = enterParams(vparams); + if (vparamSyms.length == 0) { + vparamSyms = NewArray.SymbolArray{Symbol.EMPTY_ARRAY}; + } else if (infer.isViewBounded(tparamSyms) && vparamSyms.length == 1) { + val vparamSyms1 = new Array[Array[Symbol]](2); + vparamSyms1(0) = vparamSyms(0); + vparamSyms1(1) = Symbol.EMPTY_ARRAY; + vparamSyms = vparamSyms1 + } + if (vparams.length > 0) + templ.body = desugarize.addParamAccessors( + templ.body, vparams(vparams.length - 1)); + + val constrtype: Type = makeMethodType( + tparamSyms, + vparamSyms, + Type.typeRef(sym.owner().thisType(), sym, Symbol.getType(tparamSyms))); + //System.out.println("set info " + sym.constructor() + " to " + constrtype + " was " + sym.constructor().rawInfo());//DEBUG + sym.primaryConstructor().setInfo(constrtype); + // necessary so that we can access tparams + sym.primaryConstructor().flags = + sym.primaryConstructor().flags | INITIALIZED; + + if (tpe != Tree.Empty) + sym.setTypeOfThis(new LazySelfType(sym, tpe)); + + defineTemplate(templ, sym, new Scope()); + owntype = templ.getType(); + context = prevContext; + + case Tree.ModuleDef(mods, name, _tpe, templ) => + var tpe = _tpe; + val clazz: Symbol = sym.moduleClass(); + val prevContext = pushContext( + tree, clazz.primaryConstructor(), context.scope); + defineTemplate(templ, clazz, new Scope()); + context = prevContext; + clazz.setInfo(templ.getType()); + tpe = transform(tpe, TYPEmode); + (tree.asInstanceOf[Tree.ModuleDef]).tpe = tpe; + if (tpe != Tree.Empty) + clazz.setTypeOfThis(new LazySelfType(sym, tpe)); + owntype = if (tpe == Tree.Empty) clazz.getType() else tpe.getType(); + + case Tree.DefDef(mods, name, tparams, vparams, _tpe, _rhs) => + var tpe = _tpe; + var rhs = _rhs; + var restype: Type = null; + val prevContext = pushContext(tree, sym, new Scope(context.scope)); + val tparamSyms = enterParams(tparams); + val vparamSyms = enterParams(vparams); + if (tpe != Tree.Empty) { + tpe = transform(tpe, TYPEmode); + (tree.asInstanceOf[Tree.DefDef]).tpe = tpe; + restype = tpe.getType(); + } else if (name == Names.CONSTRUCTOR) { + if (context.enclClass.owner.typeParams().length != 0) + error(tree.pos, "secondary constructors for parameterized classes not yet implemented"); + restype = context.enclClass.owner.getType();/*.subst( + context.enclClass.owner.typeParams(), tparamSyms)*/; + } else { + if ((sym.flags & PARAMACCESSOR) != 0) { + rhs.setType(rhs.symbol().getType()); + } else { + rhs = transform(rhs, EXPRmode); + (tree.asInstanceOf[Tree.DefDef]).rhs = rhs; + } + restype = rhs.getType(); + if (!sym.isFinal()) restype = restype.deconst(); + } + restype = checkNoEscape(tpe.pos, restype); + if (name == Names.view && + infer.containsSymbol(tparamSyms, restype.symbol())) { + error(tree.pos, "result type of view may not be a type variable"); + restype = definitions.ANY_TYPE(); + } + context = prevContext; + + owntype = makeMethodType(tparamSyms, vparamSyms, restype); + //System.out.println("methtype " + name + ":" + owntype);//DEBUG + addInheritedOverloaded(sym, owntype); + + case Tree.ValDef(mods, name, _tpe, _rhs) => + var tpe = _tpe; + var rhs = _rhs; + if (tpe != Tree.Empty) { + tpe = transform(tpe, TYPEmode); + (tree.asInstanceOf[Tree.ValDef]).tpe = tpe; + owntype = tpe.getType(); + } else { + val prevContext = pushContext(tree, sym, context.scope); + if (rhs == Tree.Empty) { + if ((sym.owner().flags & ACCESSOR) != 0) { + // this is the parameter of a variable setter method. + assert((sym.flags & PARAM) != 0); + owntype = sym.owner().accessed().getType(); + } else { + error(tree.pos, "missing parameter type"); + owntype = Type.ErrorType; + } + } else { + rhs = transform(rhs, EXPRmode); + (tree.asInstanceOf[Tree.ValDef]).rhs = rhs; + owntype = rhs.getType(); + if (sym.isVariable() || !sym.isFinal()) + owntype = owntype.deconst(); + } + context = prevContext; + addInheritedOverloaded(sym, owntype); + } + + case Tree.AliasTypeDef(mods, name, tparams, _rhs) => + var rhs = _rhs; + val prevContext = pushContext(tree, sym.primaryConstructor(), new Scope(context.scope)); + val tparamSyms = enterParams(tparams); + rhs = transform(rhs, TYPEmode); + (tree.asInstanceOf[Tree.AliasTypeDef]).rhs = rhs; + owntype = rhs.getType(); + sym.primaryConstructor().setInfo( + new Type$PolyType(tparamSyms, owntype)); + context = prevContext; + + case Tree.AbsTypeDef(mods, name, _rhs, _lobound) => + var rhs = _rhs; + var lobound = _lobound; + //can't have `sym' as owner since checkNonCyclic would fail. + rhs = transform(rhs, TYPEmode); + tree.asInstanceOf[Tree.AbsTypeDef].rhs = rhs; + lobound = transform(lobound, TYPEmode); + (tree.asInstanceOf[Tree.AbsTypeDef]).lobound = lobound; + if (sym.isViewBounded()) { + sym.setVuBound(rhs.getType()); + owntype = definitions.ANY_TYPE(); + } else { + owntype = rhs.getType(); + } + sym.setLoBound(lobound.getType()); + owntype.symbol().initialize();//to detect cycles todo: needed? + + case Tree.Import(_expr, selectors) => + val expr = transform(_expr, EXPRmode | QUALmode); + tree.asInstanceOf[Tree.Import].expr = expr; + checkStable(expr); + owntype = expr.getType(); + val tp: Type = owntype.widen(); + { var i = 0; while (i < selectors.length) { + if (selectors(i) != Names.IMPORT_WILDCARD && + tp.lookup(selectors(i)) == Symbol.NONE && + tp.lookup(selectors(i).toTypeName()) == Symbol.NONE) + error(tree.pos, "" + NameTransformer.decode(selectors(i)) + " is not a member of " + expr); + i = i + 2 + }} + case _ => + throw new ApplicationError(); + } + sym.setInfo(owntype); + validate(sym); + if (global.debug) global.log("defined " + sym); + } catch { + case ex: Type$Error => + reportTypeError(tree.pos, ex); + setError(tree); + if (tree.hasSymbol()) { + tree.symbol().setInfo(Type.ErrorType); + } + } + + this.unit = savedUnit; + this.context = savedContext; + this.mode = savedMode; + this.pt = savedPt; + } + + /** Definition phase for a template. This enters all symbols in template + * into symbol table. + */ + def defineTemplate(templ: Tree.Template, clazz: Symbol, members: Scope): unit = { + // attribute parent constructors + templ.parents = transformConstrInvocations(templ.pos, templ.parents); + if (templ.parents.length > 0 && + (templ.parents(0).getType().symbol().flags & (JAVA | INTERFACE)) == (JAVA | INTERFACE)) { + val constrs1 = new Array[Tree](templ.parents.length + 1); + constrs1(0) = gen.mkApply__( + gen.mkPrimaryConstructorGlobalRef( + templ.parents(0).pos, definitions.OBJECT_CLASS)); + System.arraycopy(templ.parents, 0, constrs1, 1, templ.parents.length); + templ.parents = constrs1; + } + val parents = Tree.typeOf(templ.parents); + + // enter all members + val prevContext = pushContext(templ, clazz, members); + templ.body = desugarize.Statements(unit, templ.body, false); + enterSyms(templ.body); + context = prevContext; + templ.setType(Type.compoundType(parents, members, clazz)); + } + + def makeMethodType(tparams: Array[Symbol], vparams: Array[Array[Symbol]], restpe: Type): Type = + if (tparams.length == 0 && vparams.length == 0) { + new Type$PolyType(tparams, restpe); + } else { + var result: Type = restpe; + var i = vparams.length - 1; + while (i >= 0) { + result = new Type$MethodType(vparams(i), result); + i = i - 1; + } + if (tparams.length != 0) + result = new Type$PolyType(tparams, result); + result + } + + /** Define self type of class or module `sym' + * associated with `tree' using given `unit' and `context'. + */ + def defineSelfType(sym: Symbol, clazz: Symbol, tree: Tree, unit: CompilationUnit, curcontext: Context): unit = { + val savedUnit: CompilationUnit = this.unit; + this.unit = unit; + val savedContext: Context = this.context; + this.context = curcontext; + + val selftype: Type = transform(tree, TYPEmode).getType(); + //todo: can we really make a compound type with class + val selftype1: Type = + if (clazz.getType().isSubType(selftype)) + clazz.getType() + else if (selftype.isSubType(clazz.getType())) + selftype + else if (selftype.isSingletonType() && selftype.singleDeref().symbol().isSubClass(clazz)) + selftype + else + selftype match { + case Type$CompoundType(parts, members) => + val parts1 = new Array[Type](parts.length + 1); + System.arraycopy(parts, 0, parts1, 0, parts.length); + parts1(parts.length) = clazz.getType(); + Type.compoundTypeWithOwner(clazz.owner().enclClass(), parts1, members); + + case _ => + Type.compoundTypeWithOwner( + clazz.owner().enclClass(), NewArray.Type(selftype, clazz.getType()), Scope.EMPTY); + } + if (global.debug) global.log("assigning self type " + selftype1); + sym.setInfo(selftype1); + + this.unit = savedUnit; + this.context= savedContext; + } + +// Attribution and Transform ------------------------------------------------- + + /** Turn tree type into stable type if possible and required by + * context. + */ + def mkStable(tree: Tree, pre: Type, mode: int, pt: Type): Tree = { + tree.getType() match { + case Type$ConstantType(_, value) => + return make.Literal(tree.pos, value).setType(tree.getType()) + case Type$PolyType(tparams, restp) => + if (tparams.length == 0) { + restp match { + case Type$ConstantType(_, value) => + return make.Literal(tree.pos, value).setType(tree.getType()); + case _ => + } + } + case _ => + } + if ((pt != null && pt.isStable() || + (mode & QUALmode) != 0 || + tree.getType().symbol().isModuleClass()) && + (pre != null) && pre.isStable()) { + var sym: Symbol = tree.symbol(); + tree.getType() match { + case Type$OverloadedType(alts, alttypes) => + if ((mode & FUNmode) == 0) { + try { + infer.exprAlternative(tree, alts, alttypes, pt); + sym = tree.symbol(); + } catch { + case ex: Type$Error => + reportTypeError(tree.pos, ex); + } + } + case _ => + } + if (sym.isStable()) { + tree.setType(Type.singleType(pre, sym)); + } + } + tree + } + + /** The qualifying class of a this or super + */ + def qualifyingClass(tree: Tree, name: Name): Symbol = { + if (name == TypeNames.EMPTY) { + val clazz: Symbol = context.enclClass.owner; + if (clazz != null) + clazz + else { + error(tree.pos, "" + tree + + " can be used only in a class, object, or template"); + Symbol.NONE + } + } else { + var i: Context = context; + while (i != Context.NONE && + !(i.owner.kind == CLASS && i.owner.name == name)) + i = i.outer.enclClass; + if (i != Context.NONE) + i.owner + else { + error(tree.pos, "" + name + " is not an enclosing class"); + Symbol.NONE + } + } + } + + /** Adapt tree to given mode and given prototype + */ + def adapt(tree: Tree, mode: int, pt: Type): Tree = { + //System.out.println(tree + ":" + tree.getType() + " adapt " + pt + " " + mode);//DEBUG + tree.getType() match { + case Type$OverloadedType(alts, alttypes) => + // resolve overloading + if ((mode & FUNmode) == 0) { + try { + infer.exprAlternative(tree, alts, alttypes, pt); + } catch { + case ex: Type$Error => + reportTypeError(tree.pos, ex); + } + tree.getType() match { + case Type$OverloadedType(_, _) => + // overload resolution failed bcs no alternative matched prototype. + typeError(tree.pos, tree.getType(), pt); + return errorTermTree(tree); + case _ => + } + return adapt(tree, mode, pt); + } + + case Type$PolyType(tparams, restp) => + // apply parameterless functions + // instantiate polymorphic expressions + if (tparams.length == 0) { + return adapt(constfold.tryToFold(tree.setType(restp)), mode, pt); + } else if ((mode & (FUNmode | POLYmode)) == 0) { + var tree1: Tree = null; + try { + tree1 = infer.exprInstance(tree, tparams, restp, pt); + } catch { + case ex: Type$Error => + error(tree.pos, ex.msg); + tree1 = errorTermTree(tree); + } + return adapt(tree1, mode, pt); + } + + case Type$MethodType(_, _) => + // convert unapplied methods to functions. + if ((mode & (EXPRmode | FUNmode)) == EXPRmode && + (infer.isCompatible(tree.getType(), pt) || + pt.symbol() == definitions.UNIT_CLASS)) { + checkEtaExpandable(tree.pos, tree.getType()); + if (TreeInfo.methPart(tree).symbol() == definitions.ANY_MATCH) { + error(tree.pos, "`match' needs to be applied fully"); + return errorTree(tree) + } else { + return transform(desugarize.etaExpand(tree, tree.getType()), mode, pt); + } + } else if ((mode & (CONSTRmode | FUNmode)) == CONSTRmode) { + error(tree.pos, "missing arguments for class constructor"); + return errorTermTree(tree); + } + + case _ => + } + if ((mode & PATTERNmode) != 0) { + if (tree.isType()) { + val clazz: Symbol = tree.getType().withDefaultArgs().unalias().symbol(); + + if (clazz.isCaseClass()) { + // set type to instantiated case class constructor + tree.setType(tree.getType().prefix().memberType(clazz.primaryConstructor())); + // MZ: this is a hack, but I didn't know how to do it better + if ((clazz.flags & (JAVA | CASE)) == (JAVA | CASE)) { + val altconstr = clazz.allConstructors().alternativeSymbols(); + tree.setType(tree.getType().prefix().memberType( + altconstr(altconstr.length - 1))); + } + tree.getType() match { + case Type$PolyType(tparams, restp) => + try { + infer.constructorInstance(tree, tparams, restp, pt); + //System.out.println("constr inst " + ArrayApply.toString(tparams) + restp + " against " + pt + " = " + tree.getType());//DEBUG + } catch { + case ex: Type$Error => + if (!pt.isError()) error(tree.pos, ex.msg); + setError(tree); + } + case _ => + } + } else if (clazz.isSubClass(definitions.SEQ_CLASS)) { + // set type to instantiated sequence class constructor + // todo: should we admit even supertypes of the target type? + val seqtp: Type = pt.baseType(clazz); + if (seqtp != Type.NoType) { + def seqConstructorType(paramtp: Type, resulttp: Type) = { + val constr: Symbol = resulttp.symbol().primaryConstructor(); + val param: Symbol = constr.newVParam( + tree.pos, REPEATED, Names.PATTERN_WILDCARD, + paramtp.baseType(definitions.SEQ_CLASS)); + new Type$MethodType(NewArray.Symbol(param), resulttp); + } + tree.setType(seqConstructorType(seqtp, pt)); + } else { + error(tree.pos, "expected pattern type " + pt + + " does not conform to sequence " + clazz); + return errorTermTree(tree); + } + } else if (!tree.getType().isError()) { + error(tree.pos, "" + tree.getType().symbol() + + " is neither a case class constructor nor a sequence class constructor"); + return errorTermTree(tree); + } + } + if ((mode & FUNmode) != 0) { + return tree; + } else { + val sym: Symbol = tree.symbol(); + // check that idents or selects are stable. + tree match { + case Tree.Ident(_) | Tree.Select(_, _) => + checkStable(tree); + case _ => + } + } + } else if ((mode & EXPRmode) != 0) { + if ((mode & FUNmode) != 0) { + if (tree.getType().isObjectType()) { + // insert apply method + val applyMeth: Symbol = tree.getType().lookup(Names.apply); + if (applyMeth != Symbol.NONE) { + val applyType: Type = infer.checkAccessible( + tree.pos, applyMeth, tree.getType().memberType(applyMeth), + tree, tree.getType()); + val tree1 = make.Select(tree.pos, tree, Names.apply) + .setSymbol(applyMeth) + .setType(applyType); + return adapt(tree1, mode, pt); + } + } + } else if ((mode & QUALmode) == 0) { + // check that packages and static modules are not used as values + tree match { + case Tree.Ident(_) | Tree.Select(_, _) => + val sym: Symbol = tree.symbol(); + if (sym != null && !sym.isError() && !sym.isValue()) { + error(tree.pos, "" + tree.symbol() + " is not a value"); + return errorTermTree(tree); + } + case _ => + } + } + } + + var owntype: Type = tree.getType(); + if ((mode & (CONSTRmode | FUNmode)) == (CONSTRmode) && pt != Type.AnyType) { + owntype = owntype.instanceType(); + // this works as for superclass constructor calls the expected + // type `pt' is always AnyType (see transformConstrInvocations). + } + if (!(owntype.isInstanceOf[Type$PolyType] || owntype.isSubType(pt))) { + tree match { + case Tree.Literal(constant) => + var n: int = constant match { + case AConstant$INT(value) => value + case AConstant$CHAR(value) => value + case _ => Integer.MAX_VALUE + } + val value1: AConstant = + if (pt.symbol() == definitions.BYTE_CLASS && -128 <= n && n <= 127) + AConstant.BYTE(n.asInstanceOf[byte]) + else if (pt.symbol() == definitions.SHORT_CLASS && -32768 <= n && n <= 32767) + AConstant.SHORT(n.asInstanceOf[short]) + else if (pt.symbol() == definitions.CHAR_CLASS && 0 <= n && n <= 65535) + AConstant.CHAR(n.asInstanceOf[char]) + else null; + if (value1 != null) + return gen.Literal(tree.pos, value1); + case _ => + } + if ((mode & EXPRmode) != 0) { + if (pt.symbol() == definitions.UNIT_CLASS) { + return gen.mkUnitBlock(tree); + } else if (infer.isCompatible(tree.getType(), pt)) { + tree match { + case Tree.Literal(value) => + val value1 = constfold.cast(value, pt); + if (value1 != null) + return adapt(gen.Literal(tree.pos, value1), mode, pt); + case _ => + } + val v = infer.bestView(tree.getType(), pt, Names.EMPTY); + if (v != null) return applyView(v, tree, mode, pt); + // todo: remove + val coerceMeth: Symbol = tree.getType().lookup(Names.coerce); + if (coerceMeth != Symbol.NONE) { + val coerceType = infer.checkAccessible( + tree.pos, coerceMeth, tree.getType().memberType(coerceMeth), + tree, tree.getType()); + val tree1 = make.Select(tree.pos, tree, Names.coerce) + .setSymbol(coerceMeth) + .setType(coerceType); + return adapt(tree1, mode, pt); + } + } + } + if ((mode & CONSTRmode) == 0) { + typeError(tree.pos, owntype, pt); + Type.explainTypes(owntype, pt); + setError(tree); + } // for constructors, delay until after the `new'. + } + tree + } + + /** Attribute an identifier consisting of a simple name or an outer reference. + * @param tree The tree representing the identifier. + * @param name The name of the identifier. + */ + def transformIdent(_tree: Tree, name: Name): Tree = { + var tree = _tree; + //System.out.println("transforming " + name);//DEBUG + // find applicable definition and assign to `sym' + var sym: Symbol = Symbol.NONE; + var pre: Type = null; + var qual: Tree = Tree.Empty; + var stopPos: int = Integer.MIN_VALUE; + var nextcontext: Context = context; + while (sym.kind == NONE && nextcontext != Context.NONE) { + sym = nextcontext.scope.lookup(name); + if (sym.kind != NONE) { + stopPos = sym.pos; + } else { + nextcontext = nextcontext.enclClass; + if (nextcontext != Context.NONE) { + sym = nextcontext.owner.typeOfThis().lookup(name); + if (sym.kind != NONE) { + stopPos = nextcontext.owner.pos; + } else { + nextcontext = nextcontext.outer; + } + } + } + } + + if (stopPos > tree.pos) { + // set stopPos to beginning of block enclosed in the scope which defines the + // referenced symbol. + var lastc = Context.NONE; + var c = nextcontext; + while (c.outer.scope != null && c.outer.scope.lookup(name) == sym) { + c.tree match { + case Tree.Block(_, _) | Tree.CaseDef(_, _, _) | Tree.ClassDef(_, _, _, _, _, _) | Tree.ModuleDef(_, _, _, _) => + lastc = c; + case _ => + } + c = c.outer + } + if (lastc != Context.NONE) { + //System.out.println("revising stop to [" + lastc.tree + "]; symbol = " + sym + ", context = " + nextcontext);//DEBUG + stopPos = lastc.tree.pos; + } + } + + var impcontext: Context = context.prevImport; + var lastimpcontext: Context = null; + var sym1: Symbol = Symbol.NONE; + while (sym1.kind == NONE && impcontext != Context.NONE && impcontext.tree.pos > stopPos) { + sym1 = impcontext.importedSymbol(name); + lastimpcontext = impcontext; + impcontext = impcontext.outer.prevImport; + } + + // evaluate what was found + if (sym1.kind == NONE) { + if (sym.kind == NONE) { + //System.out.println(name);//DEBUG + error(tree.pos, "not found: " + decode(name)); + return errorTree(tree); + } else { + if (sym.owner().kind == CLASS) { + pre = nextcontext.enclClass.owner.thisType(); + if (!sym.owner().isPackageClass()) { + val qual1: Tree = gen.This(tree.pos, nextcontext.enclClass.owner); + tree = make.Select(tree.pos, qual1, name); + //System.out.println(name + " :::> " + tree + " " + qual1.symbol());//DEBUG + } + } else { + pre = Type.NoPrefix; + } + } + } else if (sym.kind != NONE && !sym.isExternal()) { + error(tree.pos, + "reference to " + name + " is ambiguous;\n" + + "it is both defined in " + sym.owner() + + " and imported subsequently by \n" + lastimpcontext.tree); + return errorTree(tree); + } else { + // check that there are no other applicable imports in same scope. + while (impcontext != Context.NONE && impcontext.scope == lastimpcontext.scope) { + if (!impcontext.sameImport(lastimpcontext) && impcontext.importedSymbol(name).kind != NONE) { + error(tree.pos, + "reference to " + name + " is ambiguous;\n" + + "it is imported twice in the same scope by\n " + + lastimpcontext.tree + "\nand " + impcontext.tree); + return errorTree(tree); + } + impcontext = impcontext.outer.prevImport; + } + sym = sym1; + qual = lastimpcontext.importPrefix().duplicate(); + pre = qual.getType(); + //System.out.println(name + " => " + lastimpcontext.tree + "." + name);//DEBUG + tree = make.Select(tree.pos, qual, name); + } + + var symtype: Type = + (if (sym.isType()) sym.typeConstructor() else sym.getType()) + .asSeenFrom(pre, sym.owner()); + symtype = infer.checkAccessible( + tree.pos, sym, symtype, qual, + if (qual == Tree.Empty && sym.owner().isPackageClass()) sym.owner().getType() + else qual.getType()); + if (symtype == Type.NoType) { + error(tree.pos, "not found: " + decode(name)); + return errorTree(tree); + } + //System.out.println(name + ":" + symtype);//DEBUG + mkStable(tree.setSymbol(sym).setType(symtype), pre, mode, pt) + } + + /** Attribute a selection where `tree' is `qual.name'. + * `qual' is already attributed. + */ + def transformSelect(tree: Tree, _qual: Tree, name: Name): Tree = { + var qual = _qual; + var uninst: Array[Symbol] = Symbol.EMPTY_ARRAY; + qual.getType() match { + case Type$PolyType(tparams, restype) => + qual = infer.mkTypeApply(qual, tparams, restype, Symbol.getType(tparams)); + uninst = tparams; + case _ => + } + var sym: Symbol = qual.getType().lookup(name); + if (sym.kind == NONE) { + if (name != Names.view) { + val qtype = qual.getType().singleDeref(); + val v = infer.bestView(qtype, Type.AnyType, name); + if (v != null) { + qual = applyView(v, qual.setType(qtype), EXPRmode, Type.AnyType); + sym = qual.getType().lookup(name); + assert(sym.kind != NONE); + } else { + //System.out.println(qual.getType() + " has members " + qual.getType().members());//DEBUG + error(tree.pos, + decode(name) + " is not a member of " + qual.getType().widen()); + return errorTree(tree); + } + } + } + val qualtype = + if (qual.isInstanceOf[Tree.Super]) context.enclClass.owner.thisType() + else qual.getType(); + var symtype: Type = + (if (sym.isType()) sym.typeConstructor() else sym.getType()) + .asSeenFrom(qualtype, sym.owner()); + if (symtype == Type.NoType) { + error(tree.pos, "not found: " + decode(name)); + return errorTree(tree); + } else + symtype = infer.checkAccessible(tree.pos, sym, symtype, qual, qualtype); + //System.out.println(sym.name + ":" + symtype);//DEBUG + if (uninst.length != 0) { + def polymorphize(tp: Type): Type = tp match { + case Type$PolyType(tparams, restype) => + new Type$PolyType(tparams, polymorphize(restype)) + case Type$OverloadedType(alts, alttypes) => + val alttypes1 = new Array[Type](alttypes.length); + var i = 0; while (i < alttypes.length) { + alttypes1(i) = polymorphize(alttypes(i)); + i = i + 1 + } + new Type$OverloadedType(alts, alttypes1) + case _ => + new Type$PolyType(uninst, tp); + } + symtype = polymorphize(symtype); + } + //System.out.println(qual.getType() + ".member: " + sym + ":" + symtype);//DEBUG + val tree1: Tree = tree match { + case Tree.Select(_, _) => + copy.Select(tree, sym, qual); + case Tree.SelectFromType(_, _) => + copy.SelectFromType(tree, sym, qual) + } + mkStable(tree1.setType(symtype), qualtype, mode, pt) + } + + /** Attribute a pattern matching expression where `pattpe' is the + * expected type of the patterns and `pt' is the expected type of the + * results. + */ + def transformVisitor(tree: Tree, pattpe: Type, pt: Type): Tree = + //System.out.println("trans visitor with " + pattpe + "," + pt);//DEBUG + tree match { + case Tree.Visitor(cases) => + val cases1 = cases; + var i = 0; while (i < cases.length) { + cases1(i) = transformCase(cases(i), pattpe, pt); + i = i + 1 + } + return copy.Visitor(tree, cases1) + .setType(Type.lub(Tree.typeOf(cases1.asInstanceOf[Array[Tree]]))); + case _ => + throw new ApplicationError(); + } + + /** Attribute a case where `pattpe' is the expected type of the pattern + * and `pt' is the expected type of the result. + */ + def transformCase(tree: Tree.CaseDef, pattpe: Type, pt: Type): Tree.CaseDef = + tree match { + case Tree.CaseDef(pat, guard, body) => + val prevContext = pushContext(tree, context.owner, new Scope(context.scope)); + this.inAlternative = false; // no vars allowed below Alternative + val pat1: Tree = transform(pat, PATTERNmode, pattpe); + val guard1: Tree = + if (guard == Tree.Empty) Tree.Empty + else transform(guard, EXPRmode, definitions.boolean_TYPE()); + val body1: Tree = transform(body, EXPRmode, pt); + context = prevContext; + return copy.CaseDef(tree, pat1, guard1, body1) + .setType(body1.getType()).asInstanceOf[Tree.CaseDef]; + } + + def transformStatSeq(stats: Array[Tree], exprOwner: Symbol): Array[Tree] = { + var stats1 = stats; + var i = 0; while (i < stats.length) { + val stat: Tree = stats(i); + if (context.owner.isCompoundSym() && !TreeInfo.isDeclaration(stat)) { + error(stat.pos, "only declarations allowed here"); + } + val mode: int = if (TreeInfo.isDefinition(stat)) NOmode else EXPRmode; + var stat1: Tree = null; + if (exprOwner.kind != NONE && !TreeInfo.isDefinition(stat)) { + val prevContext = pushContext(stat, exprOwner, context.scope); + stat1 = transform(stat, mode); + context = prevContext; + } else { + stat1 = transform(stat, mode); + } + // todo: if we comment next 4 lines out, test/pos/scoping2 fails. + // find out why + if (stat1 != stat && stats1 == stats) { + stats1 = new Array[Tree](stats.length); + System.arraycopy(stats, 0, stats1, 0, i); + } + stats1(i) = stat1; + i = i + 1 + } + stats1 + } + + /** Attribute a sequence of constructor invocations. + */ + def transformConstrInvocations(pos: int, constrs: Array[Tree]): Array[Tree] = { + var i = 0; while (i < constrs.length) { + constrs(i) = transform(constrs(i), CONSTRmode | SUPERmode, Type.AnyType); + val f: Symbol = TreeInfo.methSymbol(constrs(i)); + if (f != null) { + val c: Symbol = f.constructorClass(); + if (c.kind == CLASS) { + c.initialize();//to detect cycles + if (i > 0 && (c.flags & JAVA) == 0) loadMixinCode(pos, c); + } + } + i = i + 1 + } + constrs + } + + def transformConstrInvocationArgs(constrs: Array[Tree]): unit = { + var i = 0; while (i < constrs.length) { + constrs(i) match { + case Tree.Apply(fn, args) => + if (fn.getType().isInstanceOf[Type$MethodType]) + transformArgs( + constrs(i).pos, TreeInfo.methSymbol(fn), Symbol.EMPTY_ARRAY, + fn.getType(), EXPRmode, args, Type.AnyType); + case _ => + } + i = i + 1 + } + } + + /** Attribute a template + */ + def transformTemplate(templ: Tree.Template, owner: Symbol): Tree.Template = { + //if (global.debug) global.log("transforming template of " + owner);//DEBUG + if (templ.getType() == null) + defineTemplate(templ, owner, owner.members());//may happen for mixins + //System.out.println(owner.info());//DEBUG + val parents = templ.parents; + transformConstrInvocationArgs(parents); + if (!owner.isError()) { + validateParentClasses( + parents, owner.info().parents(), owner.thisType()); + } + val prevContext = pushContext(templ, owner, owner.members()); + /* + val params: Scope = new Scope(); + def computeParams(t: Type): unit = t match { + case Type$PolyType(tparams, t1) => + var i = 0; while (i < tparams.length) { + params.enter(tparams(i)); + i = i + 1; + } + computeParams(t1); + case Type$MethodType(vparams, _) => + var i = 0; while (i < vparams.length) { + params.enter(vparams(i)); + i = i + 1; + } + case _ => + } + computeParams(owner.primaryConstructor().getType()); + val prevContext = pushContext(templ, owner.primaryConstructor(), params); + */ + templ.setSymbol(owner.newLocalDummy()); + val body1 = transformStatSeq(templ.body, templ.symbol()); + /* + context = prevContext; + */ + context = prevContext; + val templ1: Tree.Template = copy.Template(templ, parents, body1); + templ1.setType(owner.getType()); + // initialize all members; necessary to initialize overloaded symbols + val members: Array[Symbol] = owner.members().elements(); + var i = 0; while (i < members.length) { + val sym = members(i); + sym.initialize(); + //System.out.println(owner.toString() + " defines " + sym + ":" + sym.getType());//DEBUG + i = i + 1 + } + templ1 + } + + /** Attribute an argument list. + * @param pos Position for error reporting + * @param meth The symbol of the called method, or `null' if none exists. + * @param tparams The type parameters that need to be instantiated + * @param methtype The method's type w/o type parameters + * @param argMode The argument mode (either EXPRmode or PATTERNmode) + * @param args The actual arguments + * @param pt The proto-resulttype. + * @return The vector of instantiated argument types, or null if error. + */ + def transformArgs(pos: int, meth: Symbol, tparams: Array[Symbol], methtype: Type, argMode: int, args: Array[Tree], pt: Type): Array[Type] = { + //System.out.println("trans args " + meth + ArrayApply.toString(tparams.asInstanceOf[Array[Object]]) + ":" + methtype + "," + pt);//DEBUG + val argtypes = new Array[Type](args.length); + methtype match { + case Type$MethodType(params, restp) => + val formals = infer.formalTypes(params, args.length); + if (formals.length != args.length) { + error(pos, "wrong number of arguments for " + + (if (meth == null) "<function>" else meth) + + ArrayApply.toString(formals.asInstanceOf[Array[Object]], "(", ",", ")")); + return null; + } + if (tparams.length == 0) { + var i = 0; while (i < args.length) { + args(i) = transform(args(i), argMode, formals(i)); + argtypes(i) = args(i).getType().deconst(); + i = i + 1 + } + } else { + // targs: the type arguments inferred from the prototype + val targs: Array[Type] = infer.protoTypeArgs(tparams, restp, pt, params); + + // argpts: prototypes for arguments + val argpts = new Array[Type](formals.length); + var i = 0; while (i < formals.length) { + argpts(i) = formals(i).subst(tparams, targs); + i = i + 1 + } + + // transform arguments with (targs/tparams)formals as prototypes + { var i = 0; while (i < args.length) { + args(i) = transform( + args(i), argMode | POLYmode, formals(i).subst(tparams, targs)); + i = i + 1 + }} + + // targs1: same as targs except that every AnyType is mapped to + // formal parameter type. + val targs1 = new Array[Type](targs.length); + { var i = 0; while (i < targs.length) { + targs1(i) = if (targs(i) != Type.AnyType) targs(i) + else tparams(i).getType(); + i = i + 1 + }} + + { var i = 0; while (i < args.length) { + argtypes(i) = args(i).getType().deconst(); + argtypes(i) match { + case Type$PolyType(tparams1, restype1) => + argtypes(i) = infer.argumentTypeInstance( + tparams1, restype1, + formals(i).subst(tparams, targs1), + argpts(i)); + case _ => + } + i = i + 1 + }} + } + // desugarizing ident patterns + if (params.length > 0 && (params(params.length-1).flags & REPEATED) != 0) { + if ((mode & PATTERNmode) != 0) { + def desug_allIdentPatterns(trees: Array[Tree], currentOwner: Symbol): unit = { + var i = 0; while (i < trees.length) { + trees(i) match { + case Tree.Ident(name) => + if (name != Names.PATTERN_WILDCARD) { + val vble: Symbol = context.scope.lookup(name); + trees(i) = desugarize.IdentPattern(trees(i)).setSymbol(vble) + .setType(vble.getType()); + } else { + trees(i) = gen.Ident(trees(i).pos, definitions.PATTERN_WILDCARD); + } + case _ => + } + i = i + 1 + } + } + desug_allIdentPatterns(args, context.owner); + } else { + assert(args.length != params.length || + !(args(params.length-1).isInstanceOf[Tree.Sequence])); + } + } + argtypes; + + case Type$PolyType(tparams1, restp) => + var tparams2: Array[Symbol] = tparams1; + if (tparams.length != 0) { + tparams2 = new Array[Symbol](tparams.length + tparams1.length); + System.arraycopy(tparams, 0, tparams2, 0, tparams.length); + System.arraycopy(tparams1, 0, tparams2, tparams.length, tparams1.length); + } + transformArgs(pos, meth, tparams2, + infer.skipViewParams(tparams2, restp), argMode, args, pt) + + case Type.ErrorType => + var i = 0; while (i < args.length) { + args(i) = transform(args(i), argMode, Type.ErrorType); + argtypes(i) = args(i).getType().deconst(); + i = i + 1 + } + argtypes + + case Type.OverloadedType(alts, alttypes) if (alts.length == 1) => + transformArgs(pos, alts(0), tparams, alttypes(0), argMode, args, pt) + + case _ => + var i = 0; while (i < args.length) { + args(i) = transform(args(i), argMode, Type.AnyType); + argtypes(i) = args(i).getType().deconst(); + i = i + 1 + } + argtypes + } + } + + /** Atribute an expression or pattern with prototype `pt'. + * Check that expression's type conforms to `pt'. + * Resolve overloading and apply parameterless functions. + * Insert `apply' function if needed. + */ + def transform(tree: Tree, mode: int, pt: Type): Tree = { + val savedMode: int = this.mode; + val savedPt: Type = this.pt; + this.mode = mode; + this.pt = pt; + val tree1: Tree = adapt(transform(tree), mode, pt); + + //System.out.println(tree1 + ": " + tree1.getType());//DEBUG + + this.mode = savedMode; + this.pt = savedPt; + tree1 + } + + /** Transform expression or type with a given mode. + */ + def transform(tree: Tree, mode: int): Tree = { + if ((mode & (EXPRmode | PATTERNmode | CONSTRmode)) != 0) + return transform(tree, mode, Type.AnyType); + + val savedMode: int = this.mode; + this.mode = mode; + val tree1: Tree = transform(tree); + this.mode = savedMode; + + if ((mode & TYPEmode) != 0) { + val sym: Symbol = tree1.symbol(); + def typeParamCount = sym.primaryConstructor().rawInfo() match { + case t: LazyTreeType => + t.tree match { + case Tree.ClassDef(_, _, tparams, _, _, _) => tparams.length + case Tree.AliasTypeDef(_, _, tparams, _) => tparams.length + case _ => 0 + } + case _ => sym.typeParams().length + } + if ((mode & FUNmode) == 0 && sym != null && typeParamCount != 0) { + error(tree.pos, "" + sym + " takes type parameters."); + return errorTree(tree); + } +// else if (tree1.isType()) +// return gen.mkType(tree1.pos, tree1.getType()); + } + tree1 + } + + def transform(trees: Array[Tree], mode: int): Array[Tree] = { + var i = 0; while (i < trees.length) { + trees(i) = transform(trees(i), mode); + i = i + 1 + } + trees + } + + override def transform(trees: Array[Tree]): Array[Tree] = + super.transform(trees); + + override def transform(trees: Array[Tree.CaseDef]): Array[Tree.CaseDef] = + super.transform(trees); + + override def transform(trees: Array[Tree.AbsTypeDef]): Array[Tree.AbsTypeDef] = + super.transform(trees); + + override def transform(trees: Array[Tree.ValDef]): Array[Tree.ValDef] = + super.transform(trees); + + override def transform(trees: Array[Array[Tree.ValDef]]): Array[Array[Tree.ValDef]] = + super.transform(trees); + + /** The main attribution function + */ + override def transform(tree: Tree): Tree = { + //System.out.println("transforming " + tree + ":" + pt);//DEBUG + if (tree.getType() != null) { + checkDefined.all = tree; checkDefined.traverse(tree);//debug + return tree; + } + val sym: Symbol = tree.symbol(); + if (sym != null && !sym.isInitialized()) sym.initialize(); + if (global.debug && TreeInfo.isDefinition(tree)) global.log("transforming definition of " + sym); + try { + tree match { + case Tree.Empty => + tree.setType(Type.NoType) + + case Tree.Attributed(attr, definition) => + + def attrInfo(attr: Tree): AttrInfo = attr match { + case Tree.Ident(_) | Tree.Select(_, _) => + new Pair(attr.symbol(), new Array[AConstant](0)) + case Tree.Apply(fn, args) => + new Pair(attrInfo(fn).fst, attrArgInfos(args)) + case _ => + unit.error(attr.pos, "malformed attribute"); + new Pair(Symbol.NONE.newErrorClass(errorName(attr).toTypeName()), + new Array[AConstant](0)) + } + + def attrArgInfos(args: Array[Tree]): Array[AConstant] = { + val infos = new Array[AConstant](args.length); + var i = 0; while (i < args.length) { + args(i) match { + case Tree.Literal(value) => infos(i) = value; + case _ => unit.error(args(i).pos, + "attribute argument needs to be a constant; found: " + args(i) + " " + args(i).getClass()); + } + i = i + 1 + } + infos + } + + val attr1 = transform(attr, CONSTRmode, definitions.ATTRIBUTE_TYPE()); + val res = transform(definition); + val defsym = res.symbol(); + var attrs = global.mapSymbolAttr.get(defsym).asInstanceOf[List[AttrInfo]]; + if (attrs == null) attrs = List(); + global.mapSymbolAttr.put(defsym, attrInfo(attr1) :: attrs); + res + + case Tree.DocDef(comment, definition) => + transform(definition) + + case Tree.PackageDef(pkg, templ @ Tree.Template(parents, body)) => + val pkgSym: Symbol = pkg.symbol(); + if (pkgSym != null && pkgSym.isPackage()) { + val prevContext = pushContext(templ, pkgSym.moduleClass(), pkgSym.members()); + val body1: Array[Tree] = transform(body); + context = prevContext; + val templ1: Tree.Template = copy.Template(templ, parents, body1); + templ1.setType(Type.NoType).setSymbol(Symbol.NONE); + copy.PackageDef(tree, pkg, templ1) + .setType(Type.NoType); + } else { + setError(tree); + } + + case Tree.PackageDef(_, _) => + setError(tree) + + case Tree.ClassDef(_, _, tparams, vparams, tpe, templ) => + val prevContext = pushContext( + tree, sym.primaryConstructor(), new Scope(context.scope)); + reenterParams(tparams, vparams, sym.primaryConstructor().getType()); + val tparams1 = transform(tparams); + val vparams1 = transform(vparams); + checkNoEscapeParams(vparams1); + val tpe1: Tree = transform(tpe, TYPEmode); + if (vparams.length > 0 && templ.getType() == null) + templ.body = desugarize.addParamAccessors( + templ.body, vparams(vparams.length - 1)); + + val templ1: Tree.Template = transformTemplate(templ, sym); + if (sym.isTrait()) checkTraitDef(tree.pos, sym, templ1); + checkNoEscape(tree.pos, sym.info()); + context = prevContext; + copy.ClassDef(tree, sym, tparams1, vparams1, tpe1, templ1) + .setType(Type.NoType); + + case Tree.ModuleDef(_, _, tpe, templ) => + val clazz = sym.moduleClass(); + clazz.initialize(); + val prevContext = pushContext( + tree, clazz.primaryConstructor(), context.scope); + val tpe1: Tree = transform(tpe, TYPEmode); + context = prevContext; + val templ1: Tree.Template = transformTemplate(templ, sym.moduleClass()); + if (tpe1 != Tree.Empty && !templ1.getType().isSubType(tpe1.getType())) + error(tree.pos, "" + sym + " does not implement " + tpe1.getType()); + + val lclass = sym.linkedClass(); + // Taken from SymbolLoader.initializeRoot() + if (lclass != null) { + if (lclass.rawInfo().isInstanceOf[SymbolLoader]) { + lclass.setInfo(Type.ErrorType); + val allConstr = lclass.allConstructors(); + allConstr.setInfo(Type.ErrorType); + allConstr.flags = allConstr.flags | Modifiers.PRIVATE; + } + } + + copy.ModuleDef(tree, sym, tpe, templ1) + .setType(Type.NoType); + + case Tree.DefDef(_, name, tparams, vparams, tpe, rhs) => + val prevContext = pushContext(tree, sym, new Scope(context.scope)); + reenterParams(tparams, vparams, sym.getType()); + if (name == Names.CONSTRUCTOR) { + val enclClass = context.enclClass.owner; + enclClass.flags = + enclClass.flags | INCONSTRUCTOR; + enclClass.primaryConstructor().flags = + enclClass.primaryConstructor().flags | INCONSTRUCTOR; + } + val tparams1 = transform(tparams); + val vparams1 = transform(vparams); + checkNoEscapeParams(vparams1); + val tpe1: Tree = + if (tpe == Tree.Empty) gen.mkType(tree.pos, sym.getType().resultType()) + else transform(tpe, TYPEmode); + var rhs1: Tree = + if (rhs == Tree.Empty) rhs + else transform( + rhs, + if (name == Names.CONSTRUCTOR) CONSTRmode else EXPRmode, + if (name == Names.CONSTRUCTOR) definitions.void_TYPE() else tpe1.getType()); + context = prevContext; + if (name == Names.CONSTRUCTOR) { + val enclClass = context.enclClass.owner; + enclClass.flags = + enclClass.flags & ~ INCONSTRUCTOR; + enclClass.primaryConstructor().flags = + enclClass.primaryConstructor().flags & ~ INCONSTRUCTOR; + } + sym.flags = sym.flags | LOCKED; + checkNonCyclic(tree.pos, tpe1.getType()); + sym.flags = sym.flags & ~LOCKED; + copy.DefDef(tree, sym, tparams1, vparams1, tpe1, rhs1) + .setType(Type.NoType); + + case Tree.ValDef(_, _, tpe, rhs) => + assert(sym != null, tree); + val tpe1: Tree = + if (tpe == Tree.Empty) gen.mkType(tree.pos, sym.getType()) + else transform(tpe, TYPEmode); + var rhs1: Tree = rhs; + if (rhs != Tree.Empty) { + val prevContext = pushContext(tree, sym, context.scope); + rhs1 = transform(rhs, EXPRmode, tpe1.getType()); + context = prevContext; + } else if ((sym.flags & (MUTABLE | DEFERRED)) == MUTABLE) { + rhs1 = gen.mkDefaultValue(tree.pos, sym.getType()); + } + sym.flags = sym.flags | LOCKED; + checkNonCyclic(tree.pos, tpe1.getType()); + sym.flags = sym.flags & ~LOCKED; + copy.ValDef(tree, sym, tpe1, rhs1) + .setType(Type.NoType); + + case Tree.AbsTypeDef(_, _, rhs, lobound) => + val rhs1: Tree = transform(rhs, TYPEmode); + val lobound1: Tree = transform(lobound, TYPEmode); + checkNonCyclic(tree.pos, sym.getType()); + copy.AbsTypeDef(tree, sym, rhs1, lobound1) + .setType(Type.NoType); + + case Tree.AliasTypeDef(_, _, tparams, rhs) => + val prevContext = pushContext(tree, sym.primaryConstructor(), new Scope(context.scope)); + reenterParams(tparams, sym.typeParams()); + val tparams1 = transform(tparams); + val rhs1: Tree = transform(rhs, TYPEmode); + context = prevContext; + checkNonCyclic(tree.pos, sym.getType()); + copy.AliasTypeDef(tree, sym, tparams1, rhs1) + .setType(Type.NoType); + + case Tree.Import(expr, selectors) => + pushContext(tree, context.owner, context.scope); + Tree.Empty +/* + + case _ => + transform1(tree, sym) + } + } + + // extracted from transform0 to avoid overflows in GenJVM + private def transform1(tree: Tree, sym: Symbol): Tree = { + + tree match { +*/ + case Tree.Block(stats, value) => + val prevContext = pushContext(tree, context.owner, new Scope(context.scope)); + val newContext = context; + val stats1 = desugarize.Statements(unit, stats, true); + enterSyms(stats1); + context = newContext; + val curmode: int = mode; + var start: Int = 0; + var valuemode: Int = curmode; + if ((curmode & CONSTRmode) != 0) { + stats1(0) = transform(stats1(0), curmode, pt); + context.enclClass.owner.flags = context.enclClass.owner.flags & ~INCONSTRUCTOR; + start = 1; + valuemode = (curmode & ~CONSTRmode) | EXPRmode; + } + var i = start; while (i < stats1.length) { + stats1(i) = transform(stats1(i), EXPRmode); + i = i + 1 + } + val value1: Tree = transform(value, valuemode & ~(FUNmode | QUALmode), pt); + val owntype: Type = + checkNoEscape(tree.pos, value1.getType().deconst()); + context = prevContext; + copy.Block(tree, stats1, value1) + .setType(owntype); + + case Tree.Sequence(trees) => + var i = 0; while (i < trees.length) { + trees(i) = transform(trees(i), + this.mode | SEQUENCEmode, + pt); + i = i + 1 + } + copy.Sequence(tree, trees).setType(pt); + + case Tree.Alternative(choices) => + val save: boolean = this.inAlternative; + this.inAlternative = true; + + val newts = new Array[Tree](choices.length); + var i = 0; while (i < choices.length) { + newts(i) = transform(choices(i), this.mode, pt); + i = i + 1 + } + + //val tpe: Type = Type.lub(Tree.typeOf(newts)); + + this.inAlternative = save; + copy.Alternative(tree, newts).setType(pt); + + case Tree.Bind(name, body) => + var vble: Symbol = null; + if(name != Names.PATTERN_WILDCARD) { + vble = context.owner.newPatternVariable(tree.pos, name).setType(pt); + enterInScope(vble); + //System.out.println("Bind("+name+",...) enters in scope:"+Debug.show(vble)); + + patternVars.put(vble, new Boolean(this.inAlternative)); + //System.out.println("case Bind.. put symbol vble="+vble+" in scope and patternVars."); + } + val body1: Tree = transform(body); + if(name == Names.PATTERN_WILDCARD) body1 + else { + //assert body1.getType() != null; + if(TreeInfo.isSequenceValued(body1)) { + vble.setType(definitions.LIST_TYPE(pt)); + } else { + vble.setType(body1.getType()); + } + copy.Bind(tree, name, body1) + .setSymbol(vble).setType(body1.getType()); + } + + case Tree.Visitor(cases) => + if (pt.symbol().isSubClass(definitions.PARTIALFUNCTION_CLASS)) { + val pft: Type = pt.baseType(definitions.PARTIALFUNCTION_CLASS); + val pftargs = pft.typeArgs(); + if (pftargs.length == 2 && infer.isFullyDefined(pftargs(0))) { + val pattype: Type = pftargs(0); + var restype: Type = pftargs(1); + val isDefinedAtVisitor: Tree = transformVisitor( + desugarize.isDefinedAtVisitor(tree), + pattype, definitions.boolean_TYPE()); + val applyVisitor: Tree = transformVisitor(tree, pattype, restype); + if (!infer.isFullyDefined(restype)) + restype = applyVisitor.getType().deconst(); + loadMixinCode(tree.pos, definitions.PARTIALFUNCTION_CLASS); + gen.mkPartialFunction( + tree.pos, applyVisitor, isDefinedAtVisitor, + pattype, restype, context.owner); + } else { + error(tree.pos, "expected pattern type of cases could not be determined"); + errorTermTree(tree) + } + } else { + transform(desugarize.Visitor(unit, tree)) + } + + case Tree.Assign(Tree.Apply(_, _), _) => + transform(desugarize.Update(tree)) + + case Tree.Assign(lhs, rhs) => + val lhs1: Tree = transform(lhs, EXPRmode); + val varsym: Symbol = lhs1.symbol(); + if (isSetterMethod(varsym)) { + // todo: change this to require setters in same template + transform(desugarize.Assign(tree.pos, lhs, rhs)); + } else if (varsym != null && (varsym.flags & MUTABLE) != 0) { + val rhs1: Tree = transform(rhs, EXPRmode, lhs1.getType()); + copy.Assign(tree, lhs1, rhs1) + .setType(definitions.void_TYPE()); + } else { + if (!lhs1.getType().isError()) + error(tree.pos, "assignment to non-variable "); + gen.mkUnitLit(tree.pos) + } + + case Tree.If(cond, thenp, elsep) => + val cond1: Tree = transform(cond, EXPRmode, definitions.boolean_TYPE()); + var thenp1: Tree = _; + var elsep1: Tree = _; + if (elsep == Tree.Empty) { + thenp1 = transform(thenp, EXPRmode, definitions.void_TYPE()); + elsep1 = gen.mkUnitLit(tree.pos); + } else { + thenp1 = transform(thenp, EXPRmode, pt); + elsep1 = transform(elsep, EXPRmode, pt); + } + copy.If(tree, cond1, thenp1, elsep1) + .setType(Type.lub(NewArray.Type(thenp1.getType(), elsep1.getType()))); + + case Tree.Throw(expr) => + val expr1: Tree = transform( + expr, EXPRmode, definitions.THROWABLE_TYPE()); + gen.Select(tree.pos, expr1, definitions.THROWABLE_THROW); + + case Tree.Return(expr) => + if (!context.owner.isInitialized()) { + error(tree.pos, "method with return needs result type"); + errorTermTree(tree) + } else { + val enclFun: Symbol = context.owner.enclMethod(); + if (enclFun.kind == VAL && !enclFun.isConstructor()) { + val expr1: Tree = transform( + expr, EXPRmode, enclFun.getType().resultType()); + copy.Return(tree, expr1) + .setSymbol(enclFun).setType(definitions.ALL_TYPE()); + } else { + error(tree.pos, "return outside method definition"); + errorTermTree(tree) + } + } + + case Tree.New(init) => + val init1: Tree = transform(init, CONSTRmode, pt); + checkInstantiatable(tree.pos, init1.getType()); + val tree1 = gen.New(tree.pos, init1); + val clazz = tree1.getType().symbol(); + if (clazz.isAnonymousClass()) { + val parentTypes = clazz.info().parents(); + val refinement: Scope = new Scope(); + val base: Type = Type.compoundTypeWithOwner(context.enclClass.owner, parentTypes, Scope.EMPTY); + val it: Scope$SymbolIterator = clazz.members().iterator(); + while (it.hasNext()) { + val sym1: Symbol = it.next(); + val basesym1: Symbol = base.lookupNonPrivate(sym1.name); + if (!basesym1.isNone() && + sym1.kind != VAL && // todo: remove once refinements work! + !base.symbol().thisType().memberType(basesym1) + .isSameAs(sym1.getType())) + refinement.enter(sym1); + } + val owntype = + if (refinement.isEmpty() && parentTypes.length == 1) + parentTypes(0) + else + checkNoEscape( + tree.pos, + Type.compoundTypeWithOwner( + context.enclClass.owner, parentTypes, refinement)); + gen.Typed(tree1, owntype) + } else + tree1 + + case Tree.Typed(expr, tpe) => + expr match { + case Tree.Ident(n) + if (n != Names.PATTERN_WILDCARD && (mode & PATTERNmode) != 0) => + transform(desugarize.TypedPattern(tree.asInstanceOf[Tree.Typed]), + mode, + pt); + case _ => + var expr1: Tree = _; + var tpe1: Tree = _; + tpe match { + case Tree.Ident(TypeNames.WILDCARD_STAR) => + expr1 = transform( + expr, mode & baseModes, definitions.SEQ_TYPE(pt)); + val elemtps = + expr1.getType().baseType(definitions.SEQ_CLASS).typeArgs(); + val elemtp: Type = if (elemtps.length == 1) elemtps(0) + else Type.ErrorType; + + tpe1 = tpe.setType(elemtp); + case _ => + tpe1 = transform(tpe, TYPEmode); + expr1 = transform(expr, mode & baseModes, tpe1.getType()); + } + copy.Typed(tree, expr1, tpe1).setType(tpe1.getType()) + } + + case Tree.Function(vparams, body) => + val prevContext = pushContext(tree, context.owner, new Scope(context.scope)); + var restype: Type = desugarize.preFunction(vparams, pt); + enterParams(vparams); + val vparams1 = transform(vparams); + val body1: Tree = transform(body, EXPRmode, restype); + if (!infer.isFullyDefined(restype)) + restype = body1.getType().deconst(); + restype = checkNoEscape(tree.pos, restype); + context = prevContext; + gen.mkFunction(tree.pos, vparams1, body1, restype, context.owner, false); + + case Tree.TypeApply(fn, args) => + + val fn1: Tree = transform( + fn, (mode & (EXPRmode | CONSTRmode)) | FUNmode, Type.AnyType); + val args1 = transform(args, TYPEmode); + val argtypes = Tree.typeOf(args1); + + // propagate errors in arguments + var i = 0; + while (i < argtypes.length && !argtypes(i).isError()) + i = i + 1; + if (i < argtypes.length) + setError(tree); + else { + + // resolve overloading + fn1.getType() match { + case Type$OverloadedType(alts, alttypes) => + try { + infer.polyAlternative(fn1, alts, alttypes, args.length); + } catch { + case ex: Type$Error => reportTypeError(tree.pos, ex); + } + case _ => + } + + // match against arguments + fn1.getType() match { + case Type$PolyType(tparams, restp) if (tparams.length == argtypes.length) => + constfold.tryToFold( + infer.completeTypeApply( + copy.TypeApply(tree, fn1, args1) + .setType(restp.subst(tparams, argtypes)))); + + case Type.ErrorType => + setError(tree) + + case fn1tp => + if (!fn1tp.isError()) error(tree.pos, + infer.toString(fn1.symbol(), fn1.getType()) + + " cannot be applied to " + + ArrayApply.toString( + argtypes.asInstanceOf[Array[Object]], "(", ",", ")")); + errorTermTree(tree) + } + } + + case Tree.Apply(fn, args) => + mode = mode & ~SEQUENCEmode; + var fn1: Tree = _; + var argMode: int = _; + var selfcc: boolean = false; + //todo: Should we pass in both cases a methodtype with + // AnyType's for args as a prototype? + if ((mode & EXPRmode) != 0) { + fn1 = transform(fn, mode | FUNmode, Type.AnyType); + argMode = EXPRmode; + } else if ((mode & PATTERNmode) != 0) { + fn1 = transform(fn, mode | FUNmode, pt); + argMode = PATTERNmode; + } else { + assert((mode & CONSTRmode) != 0); + fn1 = transform(fn, mode | FUNmode, Type.AnyType); + argMode = EXPRmode; + + // convert type to constructor + val tsym: Symbol = TreeInfo.methSymbol(fn1); + if (!tsym.isError()) { + assert(tsym.isType(), tsym); + fn1.getType().withDefaultArgs().unalias() match { + case Type$TypeRef(pre, c, argtypes) => + if (c.kind != CLASS) { + error(tree.pos, + "" + tsym + " is not a class; cannot be instantiated"); + } else if (!pre.isStable()) { + error(tree.pos, "" + pre + " is not a legal prefix for a constructor"); + } else { + c.initialize(); + val constr: Symbol = c.allConstructors(); + val fn0: Tree = fn1; + fn1 = gen.mkRef(fn1.pos, pre, constr); + var enclClassOrConstructorContext = Context.NONE; + if (constr.owner().isPackageClass()) { + var c = context; + while (c != Context.NONE && + !c.tree.isInstanceOf[Tree.ClassDef] && + !c.tree.isInstanceOf[Tree.ModuleDef] && + !c.tree.isInstanceOf[Tree.Template]) + c = c.outer; + enclClassOrConstructorContext = c + } + if (enclClassOrConstructorContext == Context.NONE) { + fn1 match { + case Tree.Select(fn1qual, _) => + fn1.setType(infer.checkAccessible( + fn1.pos, constr, fn1.getType(), fn1qual, fn1qual.getType())); + case _ => + if (constr.owner().isPackageClass()) + fn1.setType(infer.checkAccessible( + fn1.pos, constr, fn1.getType(), Tree.Empty, constr.owner().getType())); + } + } else { + val cowner = enclClassOrConstructorContext.owner; + if (cowner.isConstructor()) + // we are in a superclass constructor call + fn1.setType( + infer.checkAccessible( + fn1.pos, constr, fn1.getType(), + make.Super(tree.pos, + Names.EMPTY.toTypeName(), + Names.EMPTY.toTypeName()), + cowner.constructorClass().typeConstructor())); + else + fn1.setType(infer.checkAccessible( + fn1.pos, constr, fn1.getType(), + enclClassOrConstructorContext.tree, + cowner.typeConstructor())); + } + if (tsym == c) { + fn0 match { + case Tree.AppliedType(_, targs) => + fn1 = infer.completeTypeApply(gen.TypeApply(fn1, targs)); + case _ => + } + } else { + // it was an alias type + // todo: handle overloaded constructors + if (argtypes.length != 0) + fn1 = gen.TypeApply( + fn1, gen.mkTypes(fn1.pos, argtypes)); + if (tsym.typeParams().length != 0 && + !(fn0.isInstanceOf[Tree.AppliedType])) + fn1.setType(new Type$PolyType( + tsym.typeParams(), fn1.getType())); + } + //System.out.println(TreeInfo.methSymbol(fn1) + ":" + tp + " --> " + fn1.getType() + " of " + fn1);//DEBUG + selfcc = TreeInfo.isSelfConstrCall(fn0); + } + + case _ => + error(tree.pos, + "" + tsym + " is not a class; cannot be instantiated"); + } + } + } + + // if function is overloaded with one alternative + // whose arity matches argument length and whose result type matches prototype, + // preselect this alternative. + fn1.getType() match { + case Type$OverloadedType(alts, alttypes) => + val argtypes = new Array[Type](args.length); + { var i = 0; while (i < argtypes.length) { + argtypes(i) = definitions.ALL_TYPE(); i = i + 1 + }} + var matching1: int = -1; + var matching2: int = -1; + { var i = 0; while (i < alttypes.length) { + if (infer.isApplicable(alttypes(i), argtypes, pt)) { + //System.out.println("matches: " + alttypes(i) + " with " + pt);//debug + matching2 = matching1; + matching1 = i; + } + i = i + 1; + }} + if (matching1 >= 0 && matching2 < 0) { + fn1.setSymbol(alts(matching1)).setType(alttypes(matching1)); + } + case _ => + } + + def handleApply: Tree = { + // handle the case of application of match to a visitor specially + if (args.length == 1 && args(0).isInstanceOf[Tree.Visitor]) { + val pattp: Type = matchQualType(fn1); + if (pattp.isError()) { + return setError(tree) + } else if (pattp != Type.NoType) { + if (infer.isFullyDefined(pattp) && + !(fn1.getType().isInstanceOf[Type$PolyType] && + pattp.containsSome(fn1.getType().typeParams()))) { + val fn2: Tree = desugarize.postMatch(fn1, context.enclClass.owner); + val arg1: Tree = transformVisitor(args(0), pattp, pt); + return copy.Apply(tree, fn2, NewArray.Tree(arg1)) + .setType(arg1.getType()); + } else { + error(tree.pos, "expected pattern type of cases could not be determined"); + return errorTermTree(tree) + } + } + } + + // return prematurely if function is a superclass constructor + // and no type arguments need to be inferred. + if ((mode & SUPERmode) != 0 && fn1.getType().isInstanceOf[Type$MethodType]) { + return copy.Apply(tree, fn1, args).setType(fn1.getType().resultType()) : Tree; + } + + // type arguments with formals as prototypes if they exist. + fn1.setType(infer.freshInstance(fn1.getType())); + val argtypes = transformArgs( + tree.pos, fn1.symbol(), Symbol.EMPTY_ARRAY, fn1.getType(), argMode, args, pt); + + if (argtypes == null) + return setError(tree) + else { + var i: int = 0; + while (i < argtypes.length && !argtypes(i).isError()) + i = i + 1; + if (i < argtypes.length) return setError(tree); + } + + // resolve overloading1g + fn1.getType() match { + case Type$OverloadedType(alts, alttypes) => + try { + infer.methodAlternative(fn1, alts, alttypes, argtypes, pt); + } catch { + case ex: Type$Error => reportTypeError(tree.pos, ex); + } + case _ => + } + + // check that self constructors go backwards. + if (selfcc) { + val constr: Symbol = TreeInfo.methSymbol(fn1); + if (constr != null && constr.kind == VAL && + !(constr.getType().isInstanceOf[Type$OverloadedType]) && + constr.pos > tree.pos) + error(tree.pos, + "illegal forward reference to self constructor"); + } + + fn1.getType() match { + case Type$PolyType(tparams, restp) => + // if method is polymorphic, + // infer instance, and adapt arguments to instantiated formals + try { + fn1 = infer.methodInstance(fn1, tparams, restp, argtypes, pt); + //System.out.println(fn1 + ":" + fn1.getType());//DEBUG + } catch { + case ex: Type$Error => + //ex.printStackTrace();//DEBUG + reportTypeError(tree.pos, ex); + } + case _ => + } + + fn1.getType() match { + case Type$MethodType(params, restp) => + if ((mode & PATTERNmode) != 0) { + return copy.Apply(tree, fn1, args).setType(restp); + } else { + val formals = infer.formalTypes(params, args.length); + if (formals.length == args.length) { + var i = 0; while (i < args.length) { + args(i) = adapt(args(i), argMode, formals(i)); + args(i) match { + case Tree.Typed( arg, Tree.Ident( TypeNames.WILDCARD_STAR ) ) => + if( i != args.length - 1 ) { + error( arg.pos, "escape only allowed in last position"); + } else if ( args.length > params.length ) { + error( arg.pos, "escaping cannot be mixed with values"); + } + case _ => /* nop */ + } + i = i + 1 + } + } + return constfold.tryToFold( + copy.Apply(tree, fn1, args) + .setType(restp)); + } + + case _ => + } + + if (!fn1.getType().isError()) + error( + tree.pos, + infer.applyErrorMsg( + "", fn1, " cannot be applied to ", argtypes, pt)); + errorTermTree(tree) + } + + handleApply + + case Tree.Super(qualifier, mixin) => + val clazz: Symbol = qualifyingClass(tree, qualifier); + if (clazz.isNone()) { + setError(tree); + } else { + tree.setSymbol(clazz); + val parents = clazz.parents(); + if (mixin == TypeNames.EMPTY) { + tree.setType(parents(0).instanceType()); + } else { + var i = 0; + while (i < parents.length && parents(i).symbol().name != mixin) + i = i + 1; + if (i < parents.length) + tree.setType(parents(i).instanceType()); + else { + error(tree.pos, + "" + mixin + " does not name a mixin base class of " + clazz); + errorTermTree(tree) + } + } + } + + case Tree.This(name) => + val clazz: Symbol = qualifyingClass(tree, name); + if (clazz.isNone()) + setError(tree) + else { + tree.setSymbol(clazz); + tree.setType( + if (pt != null && pt.isStable() || (mode & QUALmode) != 0) clazz.thisType() + else clazz.typeOfThis()); + } + + case Tree.Select(qual, name) => + val qualmode: int = if (name == Names._match) EXPRmode + else EXPRmode | POLYmode | QUALmode; + var qual1: Tree = transform(qual, qualmode); + if (name.isTypeName()) + qual1 = checkStable(qual1); + transformSelect( + tree, adapt(qual1, qualmode, Type.AnyType), name); + + case Tree.Ident(name) => + if (name == Names.CONSTRUCTOR) { + assert((mode & CONSTRmode) != 0, tree); + copy.Ident(tree, context.enclClass.owner) + .setType(context.enclClass.owner.getType()); + } else if (((mode & (PATTERNmode | FUNmode)) == PATTERNmode) && name.isVariable()) { + var vble: Symbol = null; + var vble2: Symbol = null; + + // if vble is bound with @, there is already a symbol + if (name != Names.PATTERN_WILDCARD) { + vble2 = context.scope.lookup(name); + } + var tree1 = tree; + if (patternVars.containsKey(vble2)) + vble = vble2; + else { + vble = + if (name == Names.PATTERN_WILDCARD) + definitions.PATTERN_WILDCARD + else context.owner.newPatternVariable(tree.pos, name).setType(pt); + //if(((mode & SEQUENCEmode) != 0)&&(name != Names.PATTERN_WILDCARD)) { + if(name != Names.PATTERN_WILDCARD) { + // x => x @ _ in sequence patterns + tree1 = desugarize.IdentPattern(tree); + } + } + if (name != Names.PATTERN_WILDCARD) enterInScope(vble); + tree1.setSymbol(vble).setType(pt); + } else { + transformIdent(tree, name) + } + + case Tree.Literal(value) => + tree.setType(Type.constantType(value)) + + case Tree.LabelDef(name, params, body) => + assert(params.length == 0); + val prevContext = pushContext(tree, context.owner, new Scope(context.scope)); + val lsym: Symbol = context.owner.newLabel(tree.pos, name); + lsym.setInfo( + new Type$MethodType(Symbol.EMPTY_ARRAY, definitions.void_TYPE())); + context.scope.enter(lsym); + val body1: Tree = transform(body, mode, pt); + context = prevContext; + copy.LabelDef(tree, lsym, params, body1) + .setSymbol(lsym).setType(definitions.void_TYPE()); + + case Tree.TypeTerm() => + tree + + case Tree.SingletonType(ref) => + val ref1: Tree = checkStable( + transform(ref, EXPRmode | QUALmode, definitions.ANYREF_TYPE())); + copy.SingletonType(tree, ref1) + .setType(ref1.getType().resultType()); + + case Tree.SelectFromType(qual, name) => + val qual1: Tree = transform(qual, TYPEmode); + transformSelect(tree, qual1, name); + + case Tree.CompoundType(parents, refinements) => + val parents1 = transform(parents, TYPEmode); + val ptypes = new Array[Type](parents1.length); + { var i = 0; while (i < parents1.length) { + val tp = parents(i).getType(); + if (i > 0 || tp.unalias().symbol().kind != TYPE) + checkClassType(parents(i).pos, tp); + ptypes(i) = tp; + i = i + 1 + }} + val members: Scope = new Scope(); + val cowner = + if (context.owner.isPrimaryConstructor() && context.owner.owner().isPackageClass()) + context.owner.constructorClass() + else context.enclClass.owner; + val self: Type = Type.compoundTypeWithOwner(cowner, ptypes, members); + val clazz: Symbol = self.symbol(); + val prevContext = pushContext(tree, clazz, members); + { var i = 0; while (i < refinements.length) { + val m = enterSym(refinements(i)); + m.flags = m.flags | OVERRIDE; + i = i + 1 + }} + val refinements1 = transformStatSeq(refinements, Symbol.NONE); + context = prevContext; + copy.CompoundType(tree, parents1, refinements1) + .setType(self) + + case Tree.AppliedType(tpe, args) => + val tpe1: Tree = transform(tpe, mode | FUNmode); + val args1 = transform(args, TYPEmode); + val argtypes = Tree.typeOf(args); + val tparams = tpe1.getType().symbol().typeParams(); + var owntype: Type = Type.ErrorType; + if (!tpe1.getType().isError()) { + if (tparams.length == args.length) + owntype = Type.appliedType(tpe1.getType(), argtypes); + else if (tparams.length == 0) + error(tree.pos, "" + tpe1.getType() + " does not take type parameters"); + else + error(tree.pos, "wrong number of type arguments for " + + tpe1.getType()); + } + copy.AppliedType(tree, tpe1, args1).setType(owntype); + + case Tree.FunType(_, _) => + transform(desugarize.FunType(tree)) + + case _ => + throw new ApplicationError("illegal tree: " + tree) + } + } catch { + case ex: Type$Error => + reportTypeError(tree.pos, ex); + errorTree(tree) + } + } +} +} + +// LocalWords: SOcos diff --git a/sources/scala/tools/nsc/util/CharArrayReader.scala b/sources/scala/tools/nsc/util/CharArrayReader.scala new file mode 100644 index 0000000000..c8202aaa7a --- /dev/null +++ b/sources/scala/tools/nsc/util/CharArrayReader.scala @@ -0,0 +1,82 @@ +package scala.tools.nsc.util; + +import scala.tools.util.SourceFile.{LF, FF, CR, SU} + +class CharArrayReader(buf: Array[char], start: int, startline: int, startcol: int, + decodeUni: boolean, error: String => unit) { + + def this(buf: Array[char], decodeUni: boolean, error: String => unit) = + this(buf, 0, 1, 1, decodeUni, error); + + /** layout constant + */ + val tabinc = 8; + + /** the line and column position of the current character + */ + var ch: char = _; + var bp = start; + var cline: int = _; + var ccol: int = _; + private var nextline = startline; + private var nextcol = startcol; + + def hasNext: boolean = bp < buf.length; + + def next: unit = { + cline = nextline; + ccol = nextcol; + ch = buf(bp); + bp = bp + 1; + ch match { + case '\t' => + nextcol = ((nextcol - 1) / tabinc * tabinc) + tabinc + 1; + case CR => + nextline = nextline + 1; + nextcol = 1; + if (buf(bp) == LF) { + ch = LF; + bp = bp + 1 + } + case LF | FF => + nextline = nextline + 1; + nextcol = 1 + case '\\' => + def evenSlashPrefix: boolean = { + var p = bp - 2; + while (p >= 0 && buf(p) == '\\') p = p - 1; + p % 2 == 0 + } + def udigit: int = { + val d = digit2int(buf(bp), 16); + if (d >= 0) { bp = bp + 1; nextcol = nextcol + 1 } + else error("error in unicode escape"); + d + } + nextcol = nextcol + 1; + if (buf(bp) == 'u' && decodeUni && evenSlashPrefix) { + do { + bp = bp + 1; nextcol = nextcol + 1; + } while (buf(bp) == 'u'); + val code = udigit << 12 | udigit << 8 | udigit << 4 | udigit; + ch = code.asInstanceOf[char] + } + case _ => + nextcol = nextcol + 1 + } + } + + def copy: CharArrayReader = + new CharArrayReader(buf, bp, nextcol, nextline, decodeUni, error); + + def digit2int(ch: char, base: int): int = { + if ('0' <= ch && ch <= '9' && ch < '0' + base) + ch - '0' + else if ('A' <= ch && ch < 'A' + base - 10) + ch - 'A' + 10 + else if ('a' <= ch && ch < 'a' + base - 10) + ch - 'a' + 10 + else + -1 + } +} diff --git a/sources/scala/tools/nsc/util/FreshNameCreator.scala b/sources/scala/tools/nsc/util/FreshNameCreator.scala new file mode 100644 index 0000000000..ece9f8e05d --- /dev/null +++ b/sources/scala/tools/nsc/util/FreshNameCreator.scala @@ -0,0 +1,28 @@ +package scala.tools.nsc.util; + +import scala.collection.mutable.HashMap; + +class FreshNameCreator { + + protected var counter = 0; + protected val counters = new HashMap[String,int]; + + /** + * Create a fresh name with the given prefix. It is guaranteed + * that the returned name has never been returned by a previous + * call to this function (provided the prefix does not end in a digit). + */ + def newName(prefix: String): String = { + val count = counters.get(prefix) match { + case Some(last) => last + 1 + case None => 0 + } + counters.update(prefix, count); + prefix + count + } + + def newName(): String = { + counter = counter + 1; + "$" + counter + "$" + } +} diff --git a/sources/scala/tools/nsc/util/NameTransformer.scala b/sources/scala/tools/nsc/util/NameTransformer.scala new file mode 100755 index 0000000000..21f89f3a01 --- /dev/null +++ b/sources/scala/tools/nsc/util/NameTransformer.scala @@ -0,0 +1,91 @@ +package scala.tools.nsc.util; + +object NameTransformer { + private val nops = 128; + private val ncodes = 26 * 26; + + private class OpCodes(val op: char, val code: String, val next: OpCodes); + + private val op2code = new Array[String](nops); + private val code2op = new Array[OpCodes](ncodes); + + private def enterOp(op: char, code: String) = { + op2code(op) = code; + val c = (code.charAt(1) - 'a') * 26 + code.charAt(2) - 'a'; + code2op(c) = new OpCodes(op, code, code2op(c)) + } + + enterOp('~', "$tilde"); + enterOp('=', "$eq"); + enterOp('<', "$less"); + enterOp('>', "$greater"); + enterOp('!', "$bang"); + enterOp('#', "$hash"); + enterOp('%', "$percent"); + enterOp('^', "$up"); + enterOp('&', "$amp"); + enterOp('|', "$bar"); + enterOp('*', "$times"); + enterOp('/', "$div"); + enterOp('+', "$plus"); + enterOp('-', "$minus"); + enterOp(':', "$colon"); + enterOp('\\', "$bslash"); + + /** Replace operator symbols by corresponding "$op_name" */ + def encode(name: String): String = { + var buf: StringBuffer = null; + val len = name.length(); + var i = 0; + while (i < len) { + val c = name charAt i; + if (c < nops && op2code(c) != null) { + if (buf == null) { + buf = new StringBuffer(); + buf.append(name.substring(0, i)); + } + buf.append(op2code(c)); + } else if (buf != null) { + buf.append(c) + } + i = i + 1 + } + if (buf == null) name else buf.toString() + } + + /** Replace $op_name by corresponding operator symbol */ + def decode(name: String): String = { + //System.out.println("decode: " + name);//DEBUG + var buf: StringBuffer = null; + val len = name.length(); + var i = 0; + while (i < len) { + var ops: OpCodes = null; + val c = name charAt i; + if (c == '$' && i + 2 < len) { + val ch1 = name.charAt(i+1); + if ('a' <= ch1 && ch1 <= 'z') { + val ch2 = name.charAt(i+2); + if ('a' <= ch2 && ch2 <= 'z') { + ops = code2op((ch1 - 'a') * 26 + ch2 - 'a'); + while (ops != null && !name.startsWith(ops.code, i)) ops = ops.next; + if (ops != null) { + if (buf == null) { + buf = new StringBuffer(); + buf.append(name.substring(0, i)); + } + buf.append(ops.op); + i = i + ops.code.length() + } + } + } + } + if (ops == null) { + if (buf != null) buf.append(c); + i = i + 1 + } + } + //System.out.println("= " + (if (buf == null) name else buf.toString()));//DEBUG + if (buf == null) name else buf.toString() + } +} diff --git a/sources/scala/tools/util/ConsoleReporter.java b/sources/scala/tools/util/ConsoleReporter.java index 7abcc06bf9..d7ae018e44 100644 --- a/sources/scala/tools/util/ConsoleReporter.java +++ b/sources/scala/tools/util/ConsoleReporter.java @@ -13,8 +13,6 @@ import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintWriter; -import scala.tools.util.debug.Debug; - /** * This class implements a Reporter that displays messages on a text * console. @@ -161,7 +159,7 @@ public class ConsoleReporter extends AbstractReporter { if ("resume".startsWith(line)) return; } } catch (IOException e) { - Debug.abort("input read error"); + throw new Error("input read error"); } } |