Refactored browsing loaders so that they can be more easily reused from the builder. Review by plocinik.

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@23937 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
odersky 2011-01-09 14:48:16 +00:00
parent b6a85c6310
commit 2f3bc01a1c
2 changed files with 112 additions and 89 deletions

View File

@ -161,96 +161,8 @@ self =>
* top-level idents. Therefore, we can detect top-level symbols that have a name
* different from their source file
*/
override lazy val loaders = new SymbolLoaders {
override lazy val loaders = new BrowsingLoaders {
val global: Global.this.type = Global.this
import syntaxAnalyzer.{OutlineParser, MalformedInput}
/** In browse mode, it can happen that an encountered symbol is already
* present. For instance, if the source file has a name different from
* the classes and objects it contains, the symbol loader will always
* reparse the source file. The symbols it encounters might already be loaded
* as class files. In this case we return the one which has a sourcefile
* (and the other has not), and issue an error if both have sourcefiles.
*/
override def enterIfNew(owner: Symbol, member: Symbol, completer: SymbolLoader): Symbol = {
completer.sourcefile match {
case Some(src) =>
(if (member.isModule) member.moduleClass else member).sourceFile = src
case _ =>
}
val decls = owner.info.decls
val existing = decls.lookup(member.name)
if (existing == NoSymbol) {
decls enter member
member
} else if (existing.sourceFile == null) {
decls unlink existing
decls enter member
member
} else {
if (member.sourceFile != null) {
if (existing.sourceFile != member.sourceFile)
error(member+"is defined twice,"+
"\n in "+existing.sourceFile+
"\n and also in "+member.sourceFile)
}
existing
}
}
def browseTopLevel(root: Symbol, src: AbstractFile) {
class BrowserTraverser extends Traverser {
var packagePrefix = ""
var entered = 0
def addPackagePrefix(pkg: Tree): Unit = pkg match {
case Select(pre, name) =>
addPackagePrefix(pre)
packagePrefix += ("." + name)
case Ident(name) =>
if (packagePrefix.length != 0) packagePrefix += "."
packagePrefix += name
case _ =>
throw new MalformedInput(pkg.pos.point, "illegal tree node in package prefix: "+pkg)
}
override def traverse(tree: Tree): Unit = tree match {
case PackageDef(pkg, body) =>
addPackagePrefix(pkg)
body foreach traverse
case ClassDef(_, name, _, _) =>
if (packagePrefix == root.fullName) {
enterClass(root, name.toString, new SourcefileLoader(src))
entered += 1
} else println("prefixes differ: "+packagePrefix+","+root.fullName)
case ModuleDef(_, name, _) =>
if (packagePrefix == root.fullName) {
enterModule(root, name.toString, new SourcefileLoader(src))
entered += 1
} else println("prefixes differ: "+packagePrefix+","+root.fullName)
case _ =>
}
}
System.out.println("Browsing "+src)
val source = new BatchSourceFile(src)
val body = new OutlineParser(source).parse()
System.out.println(body)
val browser = new BrowserTraverser
browser.traverse(body)
if (browser.entered == 0)
warning("No classes or objects found in "+source+" that go in "+root)
}
override def enterToplevelsFromSource(root: Symbol, name: String, src: AbstractFile) {
try {
browseTopLevel(root, src)
} catch {
case ex: syntaxAnalyzer.MalformedInput =>
println("caught malformed input exception at offset "+ex.offset+": "+ex.msg)
super.enterToplevelsFromSource(root, name, src)
}
}
}
// ----------------- Polling ---------------------------------------

View File

@ -0,0 +1,111 @@
/* NSC -- new Scala compiler
* Copyright 2005-2010 LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc
package symtab
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.util.BatchSourceFile
/** A subclass of SymbolLoaders that implements browsing behavior.
* This class should be used whenever file dependencies and recompile sets
* are managed automoatically.
*/
abstract class BrowsingLoaders extends SymbolLoaders {
import global._
import syntaxAnalyzer.{OutlineParser, MalformedInput}
/** In browse mode, it can happen that an encountered symbol is already
* present. For instance, if the source file has a name different from
* the classes and objects it contains, the symbol loader will always
* reparse the source file. The symbols it encounters might already be loaded
* as class files. In this case we return the one which has a sourcefile
* (and the other has not), and issue an error if both have sourcefiles.
*/
override protected def enterIfNew(owner: Symbol, member: Symbol, completer: SymbolLoader): Symbol = {
completer.sourcefile match {
case Some(src) =>
(if (member.isModule) member.moduleClass else member).sourceFile = src
case _ =>
}
val decls = owner.info.decls
val existing = decls.lookup(member.name)
if (existing == NoSymbol) {
decls enter member
member
} else if (existing.sourceFile == null) {
decls unlink existing
decls enter member
member
} else {
if (member.sourceFile != null) {
if (existing.sourceFile != member.sourceFile)
error(member+"is defined twice,"+
"\n in "+existing.sourceFile+
"\n and also in "+member.sourceFile)
}
existing
}
}
/** Browse the top-level of given abstract file `src` and enter
* eny encountered top-level classes and modules in `root`
*/
def browseTopLevel(root: Symbol, src: AbstractFile) {
class BrowserTraverser extends Traverser {
var packagePrefix = ""
var entered = 0
def addPackagePrefix(pkg: Tree): Unit = pkg match {
case Select(pre, name) =>
addPackagePrefix(pre)
packagePrefix += ("." + name)
case Ident(name) =>
if (packagePrefix.length != 0) packagePrefix += "."
packagePrefix += name
case _ =>
throw new MalformedInput(pkg.pos.point, "illegal tree node in package prefix: "+pkg)
}
override def traverse(tree: Tree): Unit = tree match {
case PackageDef(pkg, body) =>
addPackagePrefix(pkg)
body foreach traverse
case ClassDef(_, name, _, _) =>
if (packagePrefix == root.fullName) {
enterClass(root, name.toString, new SourcefileLoader(src))
entered += 1
} else println("prefixes differ: "+packagePrefix+","+root.fullName)
case ModuleDef(_, name, _) =>
if (packagePrefix == root.fullName) {
enterModule(root, name.toString, new SourcefileLoader(src))
entered += 1
} else println("prefixes differ: "+packagePrefix+","+root.fullName)
case _ =>
}
}
System.out.println("Browsing "+src)
val source = new BatchSourceFile(src)
val body = new OutlineParser(source).parse()
System.out.println(body)
val browser = new BrowserTraverser
browser.traverse(body)
if (browser.entered == 0)
warning("No classes or objects found in "+source+" that go in "+root)
}
/** Enter top-level symbols from a source file
*/
override def enterToplevelsFromSource(root: Symbol, name: String, src: AbstractFile) {
try {
browseTopLevel(root, src)
} catch {
case ex: syntaxAnalyzer.MalformedInput =>
println("caught malformed input exception at offset "+ex.offset+": "+ex.msg)
super.enterToplevelsFromSource(root, name, src)
}
}
}