diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/Global.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala new file mode 100644 index 0000000000..75558c30b5 --- /dev/null +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -0,0 +1,518 @@ +/* NSC -- new scala compiler + * Copyright 2005 LAMP/EPFL + * @author Martin Odersky + */ +// $Id$ +package scala.tools.nsc; + +import java.io._; +import java.nio.charset._; +import scala.tools.util.{SourceReader,ClassPath,AbstractFile}; +import scala.tools.nsc.util.{Position,SourceFile}; +import scala.tools.nsc.reporters._; + +import scala.collection.mutable.{HashSet,HashMap} + +import symtab._; +import symtab.classfile.{PickleBuffer, Pickler}; +import util.{ListBuffer, Statistics}; +import ast._; +import ast.parser._; +import typechecker._; +import matching.TransMatcher; +import transform._; +import backend.icode.{ICodes, GenICode, Checkers}; +import backend.ScalaPrimitives; +import backend.jvm.GenJVM; + +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 treeBrowsers extends TreeBrowsers { + val global: Global.this.type = Global.this + } + val treeBrowser = treeBrowsers.create(); + + object treeInfo extends TreeInfo { + val global: Global.this.type = Global.this + } + + object gen extends TreeGen { + val global: Global.this.type = Global.this + } + + object constfold extends ConstantFolder { + val global: Global.this.type = Global.this + } + + object checker extends TreeCheckers { + val global: Global.this.type = Global.this + } + + object icodes extends ICodes { + val global: Global.this.type = Global.this + } + + object checkers extends Checkers { + val global: Global.this.type = Global.this + } + + object statistics extends Statistics { + val global: Global.this.type = Global.this + } + + object overridingPairs extends OverridingPairs { + val global: Global.this.type = Global.this + } + + val copy = new LazyTreeCopier(); + +// reporting ------------------------------------------------------- + + def error(msg: String) = reporter.error(null, msg); + def warning(msg: String) = reporter.warning(null, msg); + def inform(msg: String) = System.err.println(msg); + + //reporter.info(null, msg, true); + + def informProgress(msg: String) = + if (settings.verbose.value) inform("[" + msg + "]"); + + def informTime(msg: String, start: long) = + informProgress(msg + " in " + (System.currentTimeMillis() - start) + "ms"); + + def log(msg: Object): unit = + if (settings.log contains phase.name) inform("[log " + phase + "] " + msg); + + def abort(msg: String) = throw new Error(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.err.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) + } + + object loaders extends SymbolLoaders { + val global: Global.this.type = Global.this + } + + def rootLoader: LazyType = new loaders.PackageLoader(classPath.getRoot()); + +// Phases ------------------------------------------------------------ + + var globalPhase: Phase = NoPhase; + + val MaxPhases = 64; + + val phaseWithId = new Array[Phase](MaxPhases); + { for (val i <- List.range(0, MaxPhases)) phaseWithId(i) = NoPhase } + + abstract class GlobalPhase(prev: Phase) extends Phase(prev) { + phaseWithId(id) = this; + def run: unit = currentRun.units foreach applyPhase; + + def apply(unit: CompilationUnit): unit; + private val isErased = prev.name == "erasure" || prev.erasedTypes; + override def erasedTypes: boolean = isErased; + private val isFlat = prev.name == "flatten" || prev.flatClasses; + override def flatClasses: boolean = isFlat; + final def applyPhase(unit: CompilationUnit): unit = { + if (settings.debug.value) inform("[running phase " + name + " on " + unit + "]"); + val unit0 = currentRun.currentUnit; + currentRun.currentUnit = unit; + apply(unit); + currentRun.advanceUnit; + assert(currentRun.currentUnit == unit); + currentRun.currentUnit = unit0; + } + } + + object syntaxAnalyzer extends SyntaxAnalyzer { + val global: Global.this.type = Global.this + } + + object analyzer extends Analyzer { + val global: Global.this.type = Global.this; + } + + object superAccessors extends SuperAccessors { + val global: Global.this.type = Global.this + } + + object pickler extends Pickler { + val global: Global.this.type = Global.this + } + + object refchecks extends RefChecks { + val global: Global.this.type = Global.this; + } + + object uncurry extends UnCurry { + val global: Global.this.type = Global.this; + } + + object tailCalls extends TailCalls { + val global: Global.this.type = Global.this; + } + + object transMatcher extends TransMatcher { + val global: Global.this.type = Global.this; + } + + object explicitOuter extends ExplicitOuter { + val global: Global.this.type = Global.this; + } + + object erasure extends Erasure { + val global: Global.this.type = Global.this; + } + + object lambdaLift extends LambdaLift { + val global: Global.this.type = Global.this; + } + + object constructors extends Constructors { + val global: Global.this.type = Global.this; + } + + object flatten extends Flatten { + val global: Global.this.type = Global.this; + } + + object mixin extends Mixin { + val global: Global.this.type = Global.this; + } + + object sampleTransform extends SampleTransform { + val global: Global.this.type = Global.this; + } + + object genicode extends GenICode { + val global: Global.this.type = Global.this; + } + + object icodePrinter extends backend.icode.Printers { + val global: Global.this.type = Global.this; + } + + object scalaPrimitives extends ScalaPrimitives { + val global: Global.this.type = Global.this; + } + + object genJVM extends GenJVM { + val global: Global.this.type = Global.this; + } + + object icodeChecker extends checkers.ICodeChecker(); + + object typer extends analyzer.Typer( + analyzer.NoContext.make(EmptyTree, Global.this.definitions.RootClass, new Scope())); + + def phaseDescriptors: List[SubComponent] = List( + analyzer.namerFactory, + analyzer.typerFactory, + superAccessors, + pickler, + refchecks, + uncurry, + tailCalls, + transMatcher, + explicitOuter, + erasure, + lambdaLift, + constructors, + flatten, + mixin, + genicode, + genJVM, + sampleTransform); + + private var curRun: Run = NoRun; + override def currentRun: Run = curRun; + + class TyperRun extends Run { + override val terminalPhase : Phase = typerPhase.next.next; + //override val terminalPhase : Phase = superAccessors.next; + } + + + + class Run extends CompilerRun { + var currentUnit : CompilationUnit = _; + curRun = this; + override val firstPhase = syntaxAnalyzer.newPhase(NoPhase); + phase = firstPhase; + definitions.init; // needs firstPhase and phase to be defined != NoPhase, + // that's why it is placed here. + icodes.init; + + private var p: Phase = firstPhase; + private var stopped = false; + for (val pd <- phaseDescriptors) { + if (!stopped) { + if (!(settings.skip contains pd.phaseName)) p = pd.newPhase(p); + stopped = settings.stop contains pd.phaseName; + } + } + + // progress tracking + def progress(current : Int, total : Int) : Unit = {} + private var phasec : Int = 0; + private var unitc : Int = 0; + def advancePhase : Unit = { + unitc = 0; + phasec = phasec + 1; + refreshProgress; + } + def advanceUnit : Unit = { + unitc = unitc + 1; + refreshProgress; + } + private def refreshProgress = if (fileset.size > 0) + progress((phasec * fileset.size) + unitc, + (phaseDescriptors.length+1) * fileset.size); + + + + override val terminalPhase : Phase = new GlobalPhase(p) { + def name = "terminal"; + def apply(unit: CompilationUnit): unit = {} + } + override def phaseNamed(name: String): Phase = { + var p: Phase = firstPhase; + while (p.next != p && p.name != name) p = p.next; + if (p.name != name) NoPhase else p + } + + override val namerPhase = phaseNamed("namer"); + override val typerPhase = phaseNamed("typer"); + override val refchecksPhase = phaseNamed("refchecks"); + override val explicitOuterPhase = phaseNamed("explicitouter"); + override val erasurePhase = phaseNamed("erasure"); + override val flattenPhase = phaseNamed("flatten"); + override val mixinPhase = phaseNamed("mixin"); + + 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: Iterator[CompilationUnit] = unitbuf.elements; + + /** 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, PickleBuffer]; + + def compileSources(sources: List[SourceFile]): unit = { + val startTime = System.currentTimeMillis(); + reporter.reset; + for (val source <- sources) + addUnit(new CompilationUnit(source)); + + globalPhase = firstPhase; + while (globalPhase != terminalPhase && reporter.errors == 0) { + val startTime = System.currentTimeMillis(); + phase = globalPhase; + globalPhase.run; + if (settings.print contains globalPhase.name) treePrinter.printAll(); + if (settings.browse contains globalPhase.name) treeBrowser.browse(units); + informTime(globalPhase.description, startTime); + globalPhase = globalPhase.next; + if (settings.check contains globalPhase.name) { + phase = globalPhase; + if (globalPhase.name == "jvm") icodeChecker.checkICodes; + else checker.checkTrees; + } + if (settings.statistics.value) statistics.print(phase); + advancePhase; + } + + if (settings.Xshowcls.value != "") showDef(newTermName(settings.Xshowcls.value), false); + if (settings.Xshowobj.value != "") showDef(newTermName(settings.Xshowobj.value), true); + if (settings.Xshowicode.value) writeICode(); + + if (reporter.errors == 0) { + assert(symData.isEmpty, symData.elements.toList); +/* + for (val Pair(sym, pickled) <- symData.elements.toList) { + sym setPos Position.NOPOS; +// if (symData contains sym) { +// symData -= sym; +// symData -= sym.linkedSym; +// writeSymblFile(sym, pickled) +// } +// } +*/ + for (val Pair(sym, file) <- symSource.elements) { + sym setPos Position.NOPOS; + if (sym.isTerm) sym.moduleClass setPos Position.NOPOS; + resetPackageClass(sym.owner); + } + } else { + for (val Pair(sym, file) <- symSource.elements) { + sym.reset(new loaders.SourcefileLoader(file)); + if (sym.isTerm) sym.moduleClass.reset(loaders.moduleClassLoader); + } + } + informTime("total", startTime); + } + + def compileLate(file: AbstractFile): unit = + if (fileset == null) + throw new FatalError("No class file for " + file + " was found\n(This file cannot be loaded as a source file)"); + else if (!(fileset contains file)) { + val unit = new CompilationUnit(getSourceFile(file)); + addUnit(unit); + var localPhase = firstPhase.asInstanceOf[GlobalPhase]; + while (localPhase.id < globalPhase.id || localPhase.id <= namerPhase.id) { + atPhase(localPhase)(localPhase.applyPhase(unit)); + localPhase = localPhase.next.asInstanceOf[GlobalPhase]; + } + refreshProgress; + } + + 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()); + } + + private def resetPackageClass(pclazz: Symbol): unit = { + assert(pclazz.isPackageClass, pclazz); + atPhase(firstPhase) { + pclazz.setInfo(atPhase(typerPhase)(pclazz.info)) + } + if (!pclazz.isRoot) resetPackageClass(pclazz.owner); + } + } + + 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.member(selector) + } + } + val sym = getSym(name, module); + System.err.println("" + sym.name + ":" + + (if (module) sym.tpe.symbol.info else sym.info)) + } + + /** Returns the file with the given suffix for the given class. */ + def getFile(clazz: Symbol, suffix: String) = { + val outdirname = settings.outdir.value; + var outdir = new File(if (outdirname == "") "." else outdirname); + val filename = clazz.fullNameString('.'); + var start = 0; + var end = filename.indexOf('.', start); + while (end >= start) { + outdir = new File(outdir, filename.substring(start, end)); + if (!outdir.exists()) outdir.mkdir(); + start = end + 1; + end = filename.indexOf('.', start); + } + new File(outdir, filename.substring(start) + suffix) + } + + private def writeSymblFile(clazz: Symbol, pickled: PickleBuffer) = { + val file = getFile(clazz, ".symbl"); + try { + val stream = new FileOutputStream(file); + stream.write(pickled.bytes, 0, pickled.writeIndex); + stream.close(); + informProgress("wrote " + file); + } catch { + case ex: IOException => + if (settings.debug.value) ex.printStackTrace(); + error("could not write file " + file); + } + } + + private def writeICode(): Unit = { + val printer = new icodePrinter.TextPrinter(null); + icodes.classes.foreach((cls) => { + val file = getFile(cls.symbol, ".icode"); + try { + val stream = new FileOutputStream(file); + printer.setWriter(new PrintWriter(stream, true)); + printer.printClass(cls); + informProgress("wrote " + file); + } catch { + case ex: IOException => + if (settings.debug.value) ex.printStackTrace(); + error("could not write file " + file); + } + }); + } +} |