summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2011-01-09 14:48:16 +0000
committerMartin Odersky <odersky@gmail.com>2011-01-09 14:48:16 +0000
commit34d82221cca365ce6b57d7baaed58bac8152ac53 (patch)
treec062409d9e42ef93928bdc46a43b2966f66f39ef /src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
parent785621901acb1888f168c2b2075e85a64af70fb8 (diff)
downloadscala-34d82221cca365ce6b57d7baaed58bac8152ac53.tar.gz
scala-34d82221cca365ce6b57d7baaed58bac8152ac53.tar.bz2
scala-34d82221cca365ce6b57d7baaed58bac8152ac53.zip
Refactored browsing loaders so that they can be...
Refactored browsing loaders so that they can be more easily reused from the builder. Review by plocinik.
Diffstat (limited to 'src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala')
-rw-r--r--src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
new file mode 100644
index 0000000000..1f2553d11e
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/BrowsingLoaders.scala
@@ -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)
+ }
+ }
+}