From cfd33de80751bc0d3d4c80c140a78de0e1201c2e Mon Sep 17 00:00:00 2001 From: Sean McDirmid Date: Wed, 11 Jan 2006 08:04:06 +0000 Subject: More stuff to support hte eclipse plugin. * Added symbol positions to to the pickler. * Deprecated util/ClassPath.java to use ClassPath.scala, which allows for source attachments. -- maybe we should remove ClassPath.java since it is no longer used. * Added support for content outline. --- src/compiler/scala/tools/nsc/Global.scala | 12 +- src/compiler/scala/tools/nsc/ast/Trees.scala | 6 +- src/compiler/scala/tools/nsc/models/Models.scala | 214 +++++++++++++++++++++ .../scala/tools/nsc/models/Models.scala.xxx | 189 ------------------ .../scala/tools/nsc/models/SemanticTokens.scala | 22 +-- .../scala/tools/nsc/symtab/SymbolLoaders.scala | 137 ++++++------- .../nsc/symtab/classfile/ClassfileParser.scala | 9 + .../tools/nsc/symtab/classfile/PickleFormat.scala | 2 + .../scala/tools/nsc/symtab/classfile/Pickler.scala | 10 +- .../tools/nsc/symtab/classfile/UnPickler.scala | 18 +- .../scala/tools/nsc/typechecker/Namers.scala | 28 ++- src/compiler/scala/tools/nsc/util/ClassPath.scala | 211 ++++++++++++++++++++ src/compiler/scala/tools/nsc/util/Position.scala | 14 +- src/compiler/scala/tools/util/ZipArchive.java | 2 +- 14 files changed, 587 insertions(+), 287 deletions(-) create mode 100644 src/compiler/scala/tools/nsc/models/Models.scala delete mode 100644 src/compiler/scala/tools/nsc/models/Models.scala.xxx create mode 100644 src/compiler/scala/tools/nsc/util/ClassPath.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 3e1ce5bf50..c7a4b2926b 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -7,7 +7,8 @@ package scala.tools.nsc; import java.io._; import java.nio.charset._; -import scala.tools.util.{SourceReader,ClassPath,AbstractFile}; +import scala.tools.util.{SourceReader,AbstractFile}; +import scala.tools.nsc.util.ClassPath; import scala.tools.nsc.util.{Position,SourceFile}; import scala.tools.nsc.reporters._; @@ -116,9 +117,10 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable new SourceReader(charset.newDecoder()); } - val classPath = new ClassPath( + val classPath = new ClassPath.Build( settings.classpath.value, settings.sourcepath.value, + settings.outdir.value, settings.bootclasspath.value, settings.extdirs.value); @@ -137,7 +139,9 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable } def getSourceFile(clazz: Symbol): SourceFile = { - val f = classPath.getRoot().lookupPath( + val f = classPath.output.source.location. + /* 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"); @@ -148,7 +152,7 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable val global: Global.this.type = Global.this } - def rootLoader: LazyType = new loaders.PackageLoader(classPath.getRoot()); + def rootLoader: LazyType = new loaders.PackageLoader(classPath.root /* getRoot() */); val migrateMsg = "migration problem when moving from Scala version 1.0 to version 2.0:\n"; diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index bd853d3f93..78c1dd7365 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -20,6 +20,8 @@ mixin class Trees requires Global { def isPrivate = ((flags & PRIVATE ) != 0); def isProtected = ((flags & PROTECTED) != 0); def isVariable = ((flags & MUTABLE ) != 0); + def isArgument = ((flags & PARAM ) != 0); + def isAccessor = ((flags & ACCESSOR ) != 0); def isPublic = !isPrivate && !isProtected; def hasFlag(flag: int) = (flags & flag) != 0; def | (flag: int): Modifiers = { @@ -141,7 +143,6 @@ mixin class Trees requires Global { assert(keyword != null); if (!source.beginsWith(pos, keyword + " ")) { val p = new Position(source, pos); - // System.err.println("SYM=" + symbol + " KW=" + keyword + " LINE=" + p.lineContent + " TEXT=" + source.content(pos) + source.content(pos + 1)); if (true) return Position.NOPOS; else throw new Error(); } @@ -214,7 +215,8 @@ mixin class Trees requires Global { def keyword = if (mods.isVariable) "var" else "val"; override def namePos(source : SourceFile) = if (pos == Position.NOPOS) Position.NOPOS; - else if (source.beginsWith(pos, "val ") || source.beginsWith(pos, "var ")) source.skipWhitespace(pos + ("val ").length()); + else if (source.beginsWith(pos, "val ") || source.beginsWith(pos, "var ")) + source.skipWhitespace(pos + ("val ").length()); else if (source.content(pos) == ',') source.skipWhitespace(pos + 1); else pos; } diff --git a/src/compiler/scala/tools/nsc/models/Models.scala b/src/compiler/scala/tools/nsc/models/Models.scala new file mode 100644 index 0000000000..d1ae21ba53 --- /dev/null +++ b/src/compiler/scala/tools/nsc/models/Models.scala @@ -0,0 +1,214 @@ +/* NSC -- new scala compiler + * Copyright 2005 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: Trees.scala,v 1.35 2005/11/14 16:58:21 mcdirmid Exp $ +package scala.tools.nsc.models; + +import scala.tools.nsc.Global; +import scala.tools.nsc.ast.Trees; +import scala.tools.nsc.util.Position; +import scala.tools.nsc.symtab.Flags; +import scala.tools.nsc.symtab.Names; + +class Models(val global : Global) { + import global._; + + abstract class Model { + } + abstract class HasTree(val parent : Composite) extends Model { + var tree : Tree = _; + def update(tree0 : Tree): Boolean = { + tree = tree0; + false; + } + def replacedBy(tree0 : Tree) : Boolean = true; + } + class ImportMod(parent0 : Composite) extends HasTree(parent0) { + def treex = tree.asInstanceOf[Import]; + + override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[Import]) { + val tree1 = tree0.asInstanceOf[Import]; + tree1.tpe == treex.tpe; + } else false; + } + + [_trait_] abstract class Composite extends Model { + import scala.collection.mutable._; + class Members extends HashSet[HasTree] /* with ObservableSet[HasTree, Members] */ { + // override def +=(elem: HasTree): Unit = super.+=(elem); + // override def -=(elem: HasTree): Unit = super.-=(elem); + // override def clear: Unit = super.clear; + } + object members extends Members; + + def isMember(tree : Tree) : Boolean = tree.isInstanceOf[Import]; // imports welcome anywhere. + + def member(tree: Tree, members : List[Tree]) : Tree = tree; + + def update0(members1 : List[Tree]) : Boolean = { + // System.err.println("update0 " + this + " " + members1); + val marked = new HashSet[HasTree]; + var updated = false; + for (val mmbr1 <- members1) if (isMember(mmbr1)) { + val mmbr2 = member(mmbr1, members1); + if (mmbr2 != null) { + var found = false; + for (val mmbr <- members) if (!found && mmbr.replacedBy(mmbr2)) { + found = true; + updated = mmbr.update(mmbr2) || updated; + marked += mmbr; + } + if (!found) { + updated = true; + val add = modelFor(mmbr2, this); + add.update(mmbr2); + members += (add); + marked += add; + } + } + // System.err.println("update1 " + this + " " + members + " " + marked); + } + val sz = members.size; + members.intersect(marked); + updated = updated || sz < members.size; + // check if anything was removed! + updated; + } + } + abstract class MemberMod(parent0 : Composite) extends HasTree(parent0) { + def treex = tree.asInstanceOf[MemberDef]; + + def name : Name = { treex.name; } + + override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[MemberDef]) { + val tree1 = tree0.asInstanceOf[MemberDef]; + treex.name == tree1.name; + } else false; + + override def update(tree0 : Tree): Boolean = { + val updated = tree == null || (treex.mods != tree0.asInstanceOf[MemberDef].mods); + super.update(tree0) || updated; + } + } + abstract class MemberComposite(parent0: Composite) extends MemberMod(parent0) with Composite; + + [_trait_] abstract class HasClassObjects extends Composite { + override def isMember(tree : Tree) : Boolean = (super.isMember(tree) || + (tree.isInstanceOf[ImplDef])); + } + abstract class ValOrDefMod(parent0: Composite) extends MemberComposite(parent0) with HasClassObjects { + def treey = tree.asInstanceOf[ValOrDefDef]; + override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ValOrDefDef]); + + override def update(tree0 : Tree): Boolean = { + val tree1 = tree0.asInstanceOf[ValOrDefDef]; + val updated = tree == null || treex.tpe != tree1.tpe; + update0(flatten(tree1.rhs, (tree2 : Tree) => isMember(tree2))); + super.update(tree0) || updated; + } + } + class ValMod(parent0: Composite) extends ValOrDefMod(parent0) { + def treez = tree.asInstanceOf[ValDef]; + override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ValDef]); + } + class DefMod(parent0: Composite) extends ValOrDefMod(parent0) { + def treez = tree.asInstanceOf[DefDef]; + + override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[DefDef]) { + val tree1 = tree0.asInstanceOf[DefDef]; + if (tree1.vparamss.length == treez.vparamss.length) { + val tpz = for (val vd <- treez.vparamss) yield for (val xd <- vd) yield xd.tpe; + val tp1 = for (val vd <- tree1.vparamss) yield for (val xd <- vd) yield xd.tpe; + tpz == tp1; + } else false; + } else false; + } + abstract class ImplMod(parent0: Composite) extends MemberComposite(parent0) with HasClassObjects { + def treey = tree.asInstanceOf[ImplDef]; + override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ImplDef]); + override def isMember(tree : Tree) : Boolean = (super.isMember(tree) || + (tree.isInstanceOf[ValOrDefDef] + /* && !tree.asInstanceOf[ValOrDefDef].mods.isPrivate */ + /* && !tree.asInstanceOf[ValOrDefDef].mods.isAccessor */) || + tree.isInstanceOf[AliasTypeDef]); + + override def member(tree : Tree, members : List[Tree]) : Tree = { + val tree0 = if (tree.isInstanceOf[DefDef]) { + val ddef = tree.asInstanceOf[DefDef]; + if (ddef.mods.isAccessor && ddef.symbol != null) { + val sym = ddef.symbol.accessed; + val ret = for (val member <- members; member.symbol == sym) yield member; + if (ret.isEmpty) tree; + else ret.head; + } else tree; + } else super.member(tree, members); + val sym = tree0.symbol; + if (sym.pos == Position.NOPOS) null; + else tree0; + } + + + def children(tree0 : Tree) : List[Tree] = tree0.asInstanceOf[ImplDef].impl.body; + + override def update(tree0 : Tree): Boolean = { + var updated = update0(children(tree0)); + (super.update(tree0) || updated); + } + } + class ClassMod(parent0: Composite) extends ImplMod(parent0) { + def treez = tree.asInstanceOf[ClassDef]; + override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ClassDef]); + } + class ObjectMod(parent0: Composite) extends ImplMod(parent0) { + def treez = tree.asInstanceOf[ModuleDef]; + override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ModuleDef]); + } + class AliasTypeMod(parent0: Composite) extends MemberMod(parent0) { + def treey = tree.asInstanceOf[AliasTypeDef]; + override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[AliasTypeDef]); + } + class AbsTypeMod(parent0: Composite) extends HasTree(parent0) { + def treey = tree.asInstanceOf[AbsTypeDef]; + override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[AbsTypeDef]); + } + class SourceMod(val original : CompilationUnit) extends Composite with HasClassObjects { + // update(unit); + def update(unit : CompilationUnit) = unit.body match { + case pdef : PackageDef => update0(pdef.stats); + case _ => + } + + override def isMember(tree : Tree) : Boolean = super.isMember(tree) || tree.isInstanceOf[Import]; + } + + def flatten0(exprs : List[Tree], filter: (Tree) => Boolean) : List[Tree] = + for (val expr <- exprs; val t : Tree <- flatten(expr,filter)) yield t; + + def flatten(expr : Tree, filter: (Tree) => Boolean) : List[Tree] = + if (filter(expr)) expr :: Nil; else expr match { + case Block(stats,last) => flatten0(stats, filter) ::: flatten(last, filter); + case If(cond,thenp,elsep) => flatten(cond,filter) ::: flatten(thenp,filter) ::: flatten(elsep,filter); + case Assign(lhs,rhs) => flatten(rhs,filter); + case CaseDef(pat,guard,body) => flatten(body,filter); + case Return(expr0) => flatten(expr0,filter); + case Throw(expr0) => flatten(expr0,filter); + case Try(block,catches,finalizer) => flatten(block,filter) ::: flatten(finalizer,filter) ::: flatten0(catches, filter); + case Match(selector,cases) => flatten(selector,filter) ::: flatten0(cases, filter); + case Apply(fun,args) => flatten(fun,filter) ::: flatten0(args,filter); + case TypeApply(fun,args) => flatten(fun,filter) ::: flatten0(args,filter); + case _ => Nil; + } + + + def modelFor(tree: Tree, parent: Composite): HasTree = tree match { + case _: ValDef => new ValMod(parent); + case _: DefDef => new DefMod(parent); + case _: ClassDef => new ClassMod(parent); + case _: ModuleDef => new ObjectMod(parent); + case _: AliasTypeDef => new AliasTypeMod(parent); + case _: AbsTypeDef => new AbsTypeMod(parent); + case _: Import => new ImportMod(parent); + } + +} diff --git a/src/compiler/scala/tools/nsc/models/Models.scala.xxx b/src/compiler/scala/tools/nsc/models/Models.scala.xxx deleted file mode 100644 index e95976ed19..0000000000 --- a/src/compiler/scala/tools/nsc/models/Models.scala.xxx +++ /dev/null @@ -1,189 +0,0 @@ -/* NSC -- new scala compiler - * Copyright 2005 LAMP/EPFL - * @author Martin Odersky - */ -// $Id: Trees.scala,v 1.35 2005/11/14 16:58:21 mcdirmid Exp $ -package scala.tools.nsc.models; - -import scala.tools.nsc.Global; -import scala.tools.nsc.ast.Trees; -import scala.tools.nsc.symtab.Flags; -import scala.tools.nsc.symtab.Names; - -[_trait_] abstract class Models { - val global : Global; - - import global._; - - abstract class Model { - } - abstract class HasTree extends Model { - var tree : Tree = _; - def update(tree0 : Tree): Boolean = { - tree = tree0; - false; - } - def replacedBy(tree0 : Tree) : Boolean = true; - } - class ImportMod extends HasTree { - def treex = tree.asInstanceOf[Import]; - - override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[Import]) { - val tree1 = tree0.asInstanceOf[Import]; - tree1.tpe == treex.tpe; - } else false; - } - - abstract class Composite extends Model { - import scala.collection.mutable._; - class Members extends HashSet[HasTree] with ObservableSet[HasTree, Members] { - override def +=(elem: HasTree): Unit = super.+=(elem); - override def -=(elem: HasTree): Unit = super.-=(elem); - override def clear: Unit = super.clear; - } - object members extends Members; - - def isMember(tree : Tree) : Boolean = false; - - def update0(members1 : List[Tree]) : Boolean = { - val marked = new HashSet[HasTree]; - var updated = false; - for (val mmbr1 <- members1) { - var found = false; - for (val mmbr <- members) if (!found && mmbr.replacedBy(mmbr1)) { - found = true; - updated = mmbr.update(mmbr1) || updated; - marked += mmbr; - } - if (!found) { - updated = true; - val add = modelFor(mmbr1); - add.update(mmbr1); - members += (add); - marked += add; - } - } - val sz = members.size; - members.intersect(marked); - updated = updated || sz < members.size; - // check if anything was removed! - updated; - } - } - abstract class MemberMod extends HasTree { - def treex = tree.asInstanceOf[MemberDef]; - def flags = new Flags.Flag(treex.mods0); - def name : Name = { treex.name0; } - - override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[MemberDef]) { - val tree1 = tree0.asInstanceOf[MemberDef]; - treex.name0 == tree1.name0; - } else false; - - override def update(tree0 : Tree): Boolean = { - val updated = tree == null || (treex.mods0 != tree0.asInstanceOf[MemberDef].mods0); - super.update(tree0) || updated; - } - } - abstract class MemberComposite extends MemberMod with Composite; - - abstract class HasClassObjects extends Composite { - override def isMember(tree : Tree) : Boolean = super.isMember(tree) || tree.isInstanceOf[ImplDef]; - } - abstract class ValOrDefMod extends MemberComposite with HasClassObjects { - def treey = tree.asInstanceOf[ValOrDefDef]; - override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ValOrDefDef]); - - override def update(tree0 : Tree): Boolean = { - val tree1 = tree0.asInstanceOf[ValOrDefDef]; - val updated = tree == null || treex.tpe != tree1.tpe; - update0(flatten(tree1.rhs0, (tree2 : Tree) => isMember(tree2))); - super.update(tree0) || updated; - } - } - class ValMod extends ValOrDefMod { - def treez = tree.asInstanceOf[ValDef]; - override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ValDef]); - } - class DefMod extends ValOrDefMod { - def treez = tree.asInstanceOf[DefDef]; - - override def replacedBy(tree0 : Tree) : Boolean = if (super.replacedBy(tree0) && tree0.isInstanceOf[DefDef]) { - val tree1 = tree0.asInstanceOf[DefDef]; - if (tree1.vparamss.length == treez.vparamss.length) { - val tpz = for (val vd <- treez.vparamss) yield for (val xd <- vd) yield xd.tpe; - val tp1 = for (val vd <- tree1.vparamss) yield for (val xd <- vd) yield xd.tpe; - tpz == tp1; - } else false; - } else false; - } - abstract class ImplMod extends MemberComposite with HasClassObjects { - def treey = tree.asInstanceOf[ImplDef]; - override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ImplDef]); - override def isMember(tree : Tree) : Boolean = super.isMember(tree) || tree.isInstanceOf[ValOrDefDef] || tree.isInstanceOf[AliasTypeDef]; - - override def update(tree0 : Tree): Boolean = { - val tree1 = tree0.asInstanceOf[ImplDef]; - - var updated = update0(tree1.impl0.body); - - // XXX: ignore parents for now! - - (super.update(tree0) || updated) && !flags.isPrivate; - } - - - } - class ClassMod extends ImplMod { - def treez = tree.asInstanceOf[ClassDef]; - override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ClassDef]); - - override def update(tree0 : Tree): Boolean = { - // XXX: type parameters and this type! - - - super.update(tree0); - } - } - class ObjectMod extends ImplMod { - def treez = tree.asInstanceOf[ModuleDef]; - override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[ModuleDef]); - } - class AliasTypeMod extends MemberMod { - def treey = tree.asInstanceOf[AliasTypeDef]; - override def replacedBy(tree0 : Tree) : Boolean = (super.replacedBy(tree0) && tree0.isInstanceOf[AliasTypeDef]); - } - class SourceMod(val unit : CompilationUnit) extends Composite with HasClassObjects { - override def isMember(tree : Tree) : Boolean = super.isMember(tree) || tree.isInstanceOf[Import]; - } - - - def flatten0(exprs : List[Tree], filter: (Tree) => Boolean) : List[Tree] = - for (val expr <- exprs; val t : Tree <- flatten(expr,filter)) yield t; - - def flatten(expr : Tree, filter: (Tree) => Boolean) : List[Tree] = - if (filter(expr)) expr :: Nil; else expr match { - case Block(stats,last) => flatten0(stats, filter) ::: flatten(last, filter); - case If(cond,thenp,elsep) => flatten(cond,filter) ::: flatten(thenp,filter) ::: flatten(elsep,filter); - case Assign(lhs,rhs) => flatten(rhs,filter); - case CaseDef(pat,guard,body) => flatten(body,filter); - case Return(expr0) => flatten(expr0,filter); - case Throw(expr0) => flatten(expr0,filter); - case Try(block,catches,finalizer) => flatten(block,filter) ::: flatten(finalizer,filter) ::: flatten0(catches, filter); - case Match(selector,cases) => flatten(selector,filter) ::: flatten0(cases, filter); - case Apply(fun,args) => flatten(fun,filter) ::: flatten0(args,filter); - case TypeApply(fun,args) => flatten(fun,filter) ::: flatten0(args,filter); - case _ => Nil; - } - - - def modelFor(tree: Tree): HasTree = tree match { - case _: ValDef => new ValMod(); - case _: DefDef => new DefMod(); - case _: ClassDef => new ClassMod(); - case _: ModuleDef => new ObjectMod(); - case _: AliasTypeDef => new AliasTypeMod(); - case _: Import => new ImportMod(); - } - -} diff --git a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala index 51d127b54b..a30b752e15 100644 --- a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala +++ b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala @@ -88,6 +88,7 @@ class SemanticTokens(val compiler: Compiler) { // already gap override def convertToGap : Pair[Int,Actual] = new Pair(0, this); } + def Process(unit : CompilationUnit) = new Process(unit); class Process(val unit : CompilationUnit) { def source = unit.source; @@ -147,8 +148,6 @@ class SemanticTokens(val compiler: Compiler) { case _ => } if (tree0.pos != Position.NOPOS) tree0 match { - - case tree : ImplDef => val pos = tree.namePos(unit.source); if (pos == Position.NOPOS) { @@ -315,15 +314,16 @@ class SemanticTokens(val compiler: Compiler) { def buildUse(term : Symbol, pos : Int) = buildSym(term, pos, false); def buildDef(term : Symbol, pos : Int) = buildSym(term, pos, true); - def buildSym(term : Symbol, pos : Int, isDef : Boolean) : Unit = if (term.hasFlag(Flags.ACCESSOR)) buildSym(term.accessed, pos, isDef) - else if (pos == Position.NOPOS) { - System.err.println("NOPOS: " + term); - Thread.dumpStack(); - } else if (term != NoSymbol) { - val name = NameTransformer.decode(term.name.toString()).toString().trim(); - val buf = unit.source.content; - val cs = name.toChars; - var idx = 0; + def buildSym(term : Symbol, pos : Int, isDef : Boolean) : Unit = + if (term.hasFlag(Flags.ACCESSOR)) buildSym(term.accessed, pos, isDef); + else if (pos == Position.NOPOS) { + System.err.println("NOPOS: " + term); + Thread.dumpStack(); + } else if (term != NoSymbol) { + val name = NameTransformer.decode(term.name.toString()).toString().trim(); + val buf = unit.source.content; + val cs = name.toChars; + var idx = 0; if (cs.length + pos > buf.length) { return; } diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index a07da4ad57..64684c80ad 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -6,7 +6,9 @@ package scala.tools.nsc.symtab; import java.io.IOException; +import java.io.File; import scala.tools.nsc.util.Position; +import scala.tools.nsc.util.ClassPath; import scala.tools.util.{AbstractFile}; import scala.tools.nsc.util.NameTransformer; import scala.collection.mutable.HashMap; @@ -25,17 +27,18 @@ abstract class SymbolLoaders { * name of file loaded for completion as a result. * Can throw an IOException on error. */ - abstract class SymbolLoader(file: AbstractFile) extends LazyType { + abstract class SymbolLoader extends LazyType { /** Load source or class file for `root', return */ protected def doComplete(root: Symbol): unit; /** The kind of file that's processed by this loader */ protected def kindString: String; private var ok = false; - - private def setSource(sym: Symbol): unit = sym match { - case clazz: ClassSymbol => clazz.sourceFile = file; - case _ => + private def setSource(sym: Symbol, sourceFile0: AbstractFile): unit = sym match { + case clazz: ClassSymbol => if (sourceFile0 != null) clazz.sourceFile = sourceFile0; + case _ => if (sourceFile0 != null) if (false) System.err.println("YYY: " + sym + " " + sourceFile0); } + def sourceFile : AbstractFile = null; + protected def sourceString : String; override def complete(root: Symbol): unit = { try { @@ -43,12 +46,16 @@ abstract class SymbolLoaders { val currentphase = phase; doComplete(root); phase = currentphase; - def source = kindString + " " + file; + def source = kindString + " " + sourceString; informTime("loaded " + source, start); if (root.rawInfo != this) { ok = true; - setSource(root.linkedModule.moduleClass); - setSource(root.linkedClass); + val sourceFile0 = if (sourceFile == null) (root match { + case clazz: ClassSymbol => clazz.sourceFile; + case _ => null; + }) else sourceFile; + setSource(root.linkedModule, sourceFile0); + setSource(root.linkedClass, sourceFile0); } else error(source + " does not define " + root) } catch { case ex: IOException => @@ -75,7 +82,11 @@ abstract class SymbolLoaders { /** Load contents of a package */ - class PackageLoader(directory: AbstractFile) extends SymbolLoader(directory) { + class PackageLoader(directory: ClassPath.Context) extends SymbolLoader { + // System.err.println("PACKAGE LOADER: " + directory); + + protected def sourceString = directory.toString(); + protected def doComplete(root: Symbol): unit = { assert(root.isPackageClass, root); root.setInfo(new PackageClassInfoType(new Scope(), root)); @@ -91,11 +102,12 @@ abstract class SymbolLoaders { root.info.decls.enter(pkg) } - def enterClassAndModule(str: String, completer: SymbolLoader, sfile : AbstractFile): unit = { + def enterClassAndModule(str: String, completer: SymbolLoader): unit = { val owner = if (root.isRoot) definitions.EmptyPackageClass else root; val name = newTermName(str); val clazz = owner.newClass(Position.NOPOS, name.toTypeName); val module = owner.newModule(Position.NOPOS, name); + if (completer.sourceFile != null) clazz.sourceFile = completer.sourceFile; clazz.setInfo(completer); module.setInfo(completer); module.moduleClass.setInfo(moduleClassLoader); @@ -104,75 +116,63 @@ abstract class SymbolLoaders { assert(clazz.linkedModule == module, module); assert(module.linkedClass == clazz, 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" && !packages.isDefinedAt(filename)) packages(filename) = file; -/* - } else if (filename.endsWith(".symbl")) { - val name = filename.substring(0, filename.length() - 6); - if (isValid(name) && - (!classes.isDefinedAt(name) || classes(name).getName().endsWith(".class"))) - classes(name) = file; -*/ - } else if (filename.endsWith(".class")) { - val name = filename.substring(0, filename.length() - 6); - if (isValid(name) && !classes.isDefinedAt(name)) - classes(name) = file; - } else if (filename.endsWith(".scala")) { - val name = filename.substring(0, filename.length() - 6); - if (isValid(name) && !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, new SourcefileLoader(sfile), sfile); - } + val classes = new HashMap[String, ClassPath.Context]; + val packages = new HashMap[String, ClassPath.Context]; + for (val dir <- directory.classes) if (dir != null) { + val it = dir.list(); + while (it.hasNext()) { + val file = it.next().asInstanceOf[AbstractFile]; + if (file.isDirectory() && directory.validPackage(file.getName()) && !packages.isDefinedAt(file.getName())) + packages(file.getName()) = directory.find(file.getName(), true); + else if (!file.isDirectory() && file.getName().endsWith(".class")) { + val name = file.getName().substring(0, file.getName().length() - (".class").length()); + if (isValid(name) && !classes.isDefinedAt(name)) + classes(name) = directory.find(name, false); + } + } } - for (val Pair(name, cfile) <- classes.elements) { - val sfile = sources.get(name) match { - case Some(sfile0) => sfile0; - case _ => null; + for (val dir <- directory.sources) if (dir != null) { + val it = dir.location.list(); + while (it.hasNext()) { + val file = it.next().asInstanceOf[AbstractFile]; + if (file.isDirectory() && directory.validPackage(file.getName()) && !packages.isDefinedAt(file.getName())) + packages(file.getName()) = directory.find(file.getName(), true); + else if (dir.compile && !file.isDirectory() && file.getName().endsWith(".scala")) { + val name = file.getName().substring(0, file.getName().length() - (".scala").length()); + if (isValid(name) && !classes.isDefinedAt(name)) + classes(name) = directory.find(name, false); + } } - sources.get(name) match { - case Some(sfile) if (sfile.lastModified() > cfile.lastModified()) => {} - case _ => - val loader = -/* if (cfile.getName().endsWith(".symbl")) new SymblfileLoader(cfile) - else */ - new ClassfileLoader(cfile); - enterClassAndModule(name, loader, sfile) - } } - for (val Pair(name, file) <- packages.elements) { - if (!sources.contains(name) && !classes.contains(name)) - enterPackage(name, new PackageLoader(file)); + //if (!packages.isEmpty) System.err.println("COMPLETE: " + packages); + //if (! classes.isEmpty) System.err.println("COMPLETE: " + classes); + // do classes first + + for (val Pair(name, file) <- classes.elements) { + val loader = if (!file.isSourceFile) new ClassfileLoader(file.file, file.sourceFile, file.sourcePath); + else new SourcefileLoader(file.file); + enterClassAndModule(name, loader); } + for (val Pair(name, file) <- packages.elements) enterPackage(name, new PackageLoader(file)); } protected def kindString: String = "directory path" } - private object classfileParser extends ClassfileParser { - val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global; - } - /* private object symblfileParser extends SymblfileParser { val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global; } */ - class ClassfileLoader(file: AbstractFile) extends SymbolLoader(file) { - protected def doComplete(root: Symbol): unit = classfileParser.parse(file, root); + class ClassfileLoader(classFile: AbstractFile, sourceFile0: AbstractFile, sourcePath0: AbstractFile) extends SymbolLoader { + private object classfileParser extends ClassfileParser { + val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global; + override def sourcePath = sourcePath0; /* could be null */ + } + protected def doComplete(root: Symbol): unit = classfileParser.parse(classFile, root); protected def kindString: String = "class file"; + protected def sourceString = classFile.toString(); + override def sourceFile : AbstractFile = sourceFile0; } /* class SymblfileLoader(file: AbstractFile) extends SymbolLoader(file) { @@ -180,14 +180,17 @@ abstract class SymbolLoaders { protected def kindString: String = "symbl file"; } */ - class SourcefileLoader(file: AbstractFile) extends SymbolLoader(file) { - protected def doComplete(root: Symbol): unit = global.currentRun.compileLate(file); + class SourcefileLoader(sourceFile0: AbstractFile) extends SymbolLoader { + protected def doComplete(root: Symbol): unit = global.currentRun.compileLate(sourceFile0); protected def kindString: String = "source file"; + override def sourceFile = sourceFile0; + protected def sourceString = sourceFile0.toString(); } - object moduleClassLoader extends SymbolLoader(null) { + object moduleClassLoader extends SymbolLoader { protected def doComplete(root: Symbol): unit = root.sourceModule.initialize; protected def kindString: String = ""; + protected def sourceString = ""; } } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index ffd5add6f0..effe6a408c 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -21,6 +21,7 @@ import scala.tools.util.AbstractFileReader; import java.io.IOException; abstract class ClassfileParser { + def sourcePath : AbstractFile = null; val global: Global; import global._; @@ -346,6 +347,14 @@ abstract class ClassfileParser { val meta = pool.getName(in.nextChar()).toString().trim(); metaParser.parse(meta, sym, symtype); this.hasMeta = true; + case nme.SourceFileATTR => + assert(attrLen == 2); + val source = pool.getName(in.nextChar()); + if (sourcePath != null) sym match { + case clazz: ClassSymbol => + clazz.sourceFile = sourcePath.lookupPath(source.toString(), false); + // System.err.println("clazz=" + clazz + " @ " + clazz.sourceFile); + } case _ => in.skip(attrLen) } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala index ea88451ef6..7709a5ba5d 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala @@ -45,6 +45,7 @@ object PickleFormat { * | 34 LITERALnull len_Nat * | 35 LITERALzero len_Nat * | 36 ATTRIBUTE sym_Ref type_Ref {constant_Ref} + * | 37 POS len_Nat sym_Ref value_Long * SymbolInfo = name_Ref owner_Ref flags_Nat [privateWithin_Ref] info_Ref * NameInfo = * NumInfo = @@ -90,6 +91,7 @@ object PickleFormat { final val LITERALstring = 33; final val LITERALnull = 34; final val LITERALzero = 35; + final val POS = 37; final val ATTRIBUTE = 40; final val firstSymTag = NONEsym; diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index 639cb71bf0..e8441dde87 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -8,9 +8,12 @@ package scala.tools.nsc.symtab.classfile; import java.io._; import java.lang.{Float, Double} import scala.collection.mutable.HashMap; +import scala.tools.nsc.util.Position; import Flags._; import PickleFormat._; + + /** * Serialize a top-level module and/or class; * @see EntryTags.scala for symbol table attribute format. @@ -77,17 +80,21 @@ abstract class Pickler extends SubComponent { ep = ep + 1; true } + case class PositionSymbol(val sym : Symbol, val pos : Int); /** Store symbol in index. If symbol is local, also store everything it refers to. */ def putSymbol(sym: Symbol): unit = if (putEntry(sym)) { if (isLocal(sym)) { putEntry(sym.name); + if (sym.pos != Position.NOPOS) putEntry(new PositionSymbol(sym, sym.pos)); + putSymbol(sym.owner); putSymbol(sym.privateWithin); putType(sym.info); if (sym.thisSym != sym) putType(sym.typeOfThis); putSymbol(sym.alias); + //for (val attr <- sym.attributes) putAttribute(sym, attr); } else if (sym != NoSymbol) { putEntry(if (sym.isModuleClass) sym.name.toTermName else sym.name); @@ -223,6 +230,7 @@ abstract class Pickler extends SubComponent { for (val c <- cs) writeRef(cs); ATTRIBUTE */ + case PositionSymbol(sym, pos) => writeRef(sym); writeLong(pos); POS; case _ => throw new FatalError("bad entry: " + entry + " " + entry.getClass());//debug } @@ -239,7 +247,7 @@ abstract class Pickler extends SubComponent { writeNat(MinorVersion); writeNat(ep); if (settings.debug.value) log("" + ep + " entries");//debug - for (val i <- Iterator.range(0, ep)) writeEntry(entries(i)) + for (val i <- Iterator.range(0, ep)) writeEntry(entries(i)); } } } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala index 3ddf7fb08f..5f268b9281 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala @@ -8,6 +8,7 @@ package scala.tools.nsc.symtab.classfile; import scala.tools.nsc.util.Position; import scala.tools.util.UTF8Codec; import java.lang.{Float, Double}; + import Flags._; import PickleFormat._; import collection.mutable.HashMap; @@ -32,8 +33,10 @@ abstract class UnPickler { private val entries = new Array[AnyRef](index.length); private val symScopes = new HashMap[Symbol, Scope]; - for (val i <- Iterator.range(0, index.length)) + for (val i <- Iterator.range(0, index.length)) { if (isSymbolEntry(i)) { at(i, readSymbol); () } + else if (isPosition(i)) { at(i, readPosition); () } + } if (settings.debug.value) global.log("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug @@ -60,12 +63,13 @@ abstract class UnPickler { (tag != CLASSsym || !isRefinementSymbolEntry(i))) } + private def isPosition(i: int): boolean = bytes(index(i)) == POS; + /** Does entry represent an (internal or external) symbol */ private def isSymbolRef(i: int): boolean = { val tag = bytes(index(i)); (firstSymTag <= tag && tag <= lastExtSymTag) } - /** Does entry represent a refinement symbol? * pre: Entry is a class symbol */ @@ -105,6 +109,16 @@ abstract class UnPickler { } } + private def readPosition(): Integer = { + val tag = readByte(); + val len = readNat(); + val start = readIndex; + val sym = readSymbolRef(); + val pos = readLong(len - (readIndex - start)).asInstanceOf[Int]; + assert(sym.pos == Position.NOPOS); + sym.setPos(pos); + new Integer(pos); + } /** Read a symbol */ private def readSymbol(): Symbol = { val tag = readByte(); diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 0c8937f1f9..ec9677f7be 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -84,8 +84,16 @@ trait Namers requires Analyzer { def enterInScope(sym: Symbol): Symbol = { if (!(sym.isSourceMethod && sym.owner.isClass)) { val prev = context.scope.lookupEntry(sym.name); - if (prev != null && prev.owner == context.scope && !prev.sym.isSourceMethod) - doubleDefError(sym.pos, prev.sym); + if (prev != null && prev.owner == context.scope && !prev.sym.isSourceMethod) { + if (sym.sourceFile == null && prev.sym.sourceFile == null) {} + else if (sym.sourceFile != null && prev.sym.sourceFile != null && + sym.sourceFile.equals(prev.sym.sourceFile)) {} + else { + System.err.println("SYM: " + sym.sourceFile); + System.err.println("PRV: " + prev.sym.sourceFile); + doubleDefError(sym.pos, prev.sym); + } + } } context.scope enter sym; sym @@ -118,8 +126,20 @@ trait Namers requires Analyzer { c = enterInScope(context.owner.newClass(pos, name)).setFlag(flags | inConstructorFlag); } if (c.owner.isPackageClass) { - currentRun.symSource(c) = context.unit.source.getFile(); - c.sourceFile = context.unit.source.getFile(); + val file = context.unit.source.getFile(); + val clazz = c.asInstanceOf[ClassSymbol]; + if (file != null) { + if (clazz.sourceFile != null && !clazz.sourceFile.equals(file)) // double def. + throw new Error(""+clazz.sourceFile + " vs. " + file + " SYM=" + c); + else clazz.sourceFile = file; + + } + if (clazz.sourceFile != null) { + if (currentRun.symSource.isDefinedAt(c) && currentRun.symSource(c) != null && + !currentRun.symSource(c).equals(clazz.sourceFile)) + throw new Error(""+currentRun.symSource(c) + " vs. " + clazz.sourceFile + " SYM=" + currentRun + " " + c); + else currentRun.symSource(c) = clazz.sourceFile; + } } c } diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala new file mode 100644 index 0000000000..a60f914ac6 --- /dev/null +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -0,0 +1,211 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2004, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.tools.nsc.util; + +import scala.tools.util.AbstractFile; +import scala.collection.mutable.ArrayBuffer; +import java.io.FileNotFoundException; +import java.io.File; +import java.util.StringTokenizer; + +/** Richer classpath abstraction than files. + * Roughly based on Eclipse's classpath abstractions. + * + * @author Sean McDirmid + */ +object ClassPath { + + class Source(val location : AbstractFile, val compile : Boolean); + + abstract class Entry { + def location : AbstractFile; + def source : Source; + } + + class Output(val location : AbstractFile, val sourceFile : AbstractFile) extends Entry { + def source = new Source(sourceFile, true); + } + class Library(val location : AbstractFile) extends Entry { + def doc : AbstractFile = null; + def sourceFile : AbstractFile = null; + def source = if (sourceFile == null) null else new Source(sourceFile, false); + } + + class Context(val classes : List[AbstractFile], val sources : List[Source]) { + def find(name : String, isDir : boolean) = { + assert(isPackage); + def find0(classes : List[AbstractFile], sources : List[Source]) : Context = { + assert(classes.length == sources.length); + if (classes.isEmpty) new Context(Nil, Nil); + else { + val ret = find0(classes.tail, sources.tail); + + val clazz = if (classes.head == null) null; else + classes.head.lookupPath(name + (if (!isDir) ".class" else ""), isDir); + + val source = { + if (sources.head == null) null; + else { + val source0 = sources.head.location.lookupPath(name + (if (!isDir) ".scala" else ""), isDir); + if (source0 != null) source0; + else if (clazz != null && !isDir) sources.head.location; // directory where we can find source. + else null; + } + } + if (clazz == null && source == null) ret; + else new Context(clazz :: ret.classes, + (if (source != null) new Source(source, sources.head.compile) else null) + :: ret.sources); + } + } + find0(classes, sources); + } + + def isPackage = { + if (classes.head != null) classes.head.isDirectory(); + else sources.head.location.isDirectory(); + } + def name = { + val name = if (classes.head != null) classes.head.getName() else sources.head.location.getName(); + if (isPackage) name; + else name.substring(0, name.length() - (".class").length()); + } + + override def toString() : String = toString(classes, sources); + + def toString(classes0 : List[AbstractFile], sources0 : List[Source]) : String = + if (classes0.isEmpty) ""; + else + ((if (classes0.head == null) "" else classes0.head.toString()) + (if (sources0.head != null) { + "::" + sources0.head.location.toString(); + } else "")) + ":" + toString(classes0.tail, sources0.tail); + + def file = { + assert(!isPackage); + if (classes.isEmpty) null; + else if (sources.head == null || sources.head.location.isDirectory() || !sources.head.compile) { + assert(classes.head != null); + classes.head; + } else if (classes.head == null) { + sources.head.location; + } else if (sources.head.location.lastModified() >= classes.head.lastModified()) sources.head.location; + else classes.head; + } + def isSourceFile = file.getName().endsWith(".scala"); + + def sourceFile = + if (sources.isEmpty || sources.head == null) null; + else if (sources.head.location.isDirectory()) null; + else sources.head.location; + + def sourcePath = + if (sources.isEmpty || sources.head == null) null; + else if (!sources.head.location.isDirectory()) null; + else sources.head.location; + + def validPackage(name : String) : Boolean = + if (name.equals("META-INF")) false; + else if (name.startsWith(".")) false; + else true; + + def complete : List[Context] = { + assert(isPackage); + def complete0(classes : List[AbstractFile], sources : List[Source]) : List[Context] = + if (classes.isEmpty) Nil; + else if (classes.head == null && sources.head == null) complete0(classes.tail, sources.tail); + else { + var ret : List[Context] = Nil; + if (classes.head != null) { + val i = classes.head.list(); + while (i.hasNext()) { + val file = i.next().asInstanceOf[AbstractFile]; + if (!file.isDirectory() && file.getName().endsWith(".class")) { + val name = file.getName().substring(0, file.getName().length() - (".class").length()); + ret = find(name, false) :: ret; + } else if (file.isDirectory() && validPackage(file.getName())) { + ret = (find(file.getName(), true) :: ret); + // System.err.println("FILE: " + file.getName() + " RET=" + ret.head); + } + } + } + if (sources.head != null && sources.head.compile) { + val j = sources.head.location.list(); + while (j.hasNext()) { + val file = j.next().asInstanceOf[AbstractFile]; + if (!file.isDirectory() && file.getName().endsWith(".scala")) { + val name = file.getName().substring(0, file.getName().length() - (".scala").length()); + if (classes.head == null || + classes.head.lookupPath(name + ".class", false) == null) ret = find(name, false) :: ret; + } else if (file.isDirectory() && validPackage(file.getName())) { + if (classes.head == null || classes.head.lookupPath(file.getName(), true) == null) + ret = find(file.getName(), true) :: ret; + } + } + } + ret ::: complete0(classes.tail, sources.tail); + } + complete0(classes, sources); + } + } + + class Build(val output : Output) { + val entries = new ArrayBuffer[Entry]; + + def root = { + val classes = for (val entry <- entries.toList) yield entry.location; + val sources = for (val entry <- entries.toList) yield entry.source; + new Context(classes, sources); + } + + + def this(classpath : String, source : String, output : String, boot : String, extdirs : String) = { + this(new Output(AbstractFile.getDirectory(output), AbstractFile.getDirectory(source))); + + if (this.output.location == null) throw new FileNotFoundException("output location \"" + output + "\" not found"); + if (this.output.source == null) throw new FileNotFoundException("source location \"" + source + "\" not found"); + + addFilesInPath(boot); + addArchivesInExtDirPath(extdirs); + entries += this.output; + addFilesInPath(classpath); + } + def library(classes : String, sources : String) = { + assert(classes != null); + val location = AbstractFile.getDirectory(classes); + val sourceFile0 = (if (sources != null) AbstractFile.getDirectory(sources) else null); + class Library0 extends Library(location) { + override def sourceFile = sourceFile0; + } + entries += new Library0(); + } + + private def addFilesInPath(path : String) = { + val strtok = new StringTokenizer(path, File.pathSeparator); + while (strtok.hasMoreTokens()) { + val file = AbstractFile.getDirectory(strtok.nextToken()); + if (file != null) entries += (new Library(file)); + } + } + private def addArchivesInExtDirPath(path : String) = { + val strtok = new StringTokenizer(path, File.pathSeparator); + while (strtok.hasMoreTokens()) { + val file = AbstractFile.getDirectory(strtok.nextToken()); + val files = (if (file != null) file.list() else null); + if (files != null) while(files.hasNext()) { + val file0 = files.next().asInstanceOf[AbstractFile]; + val name = file0.getName(); + if (name.endsWith(".jar") || name.endsWith(".zip")) { + val archive = AbstractFile.getDirectory(new File(file.getFile(), name)); + if (archive != null) entries += (new Library(archive)); + } + } + } + } + } +} diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index bf502cac3b..29f4d74cf7 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -68,12 +68,14 @@ class Position( val source : SourceFile, val offset: Int) { /** Returns a string representation of the encoded position. */ override def toString(): String = { val sb = new StringBuffer(); - sb.append(source.file.getPath()); - if (hasOffset) { - sb.append(line); - sb.append(':'); - sb.append(column); - } + if (source != null) { + sb.append(source.file.getPath()); + if (hasOffset) { + sb.append(line); + sb.append(':'); + sb.append(column); + } + } else sb.append("::" + offset); sb.toString(); } } diff --git a/src/compiler/scala/tools/util/ZipArchive.java b/src/compiler/scala/tools/util/ZipArchive.java index 6367b28013..b3cd9e6538 100644 --- a/src/compiler/scala/tools/util/ZipArchive.java +++ b/src/compiler/scala/tools/util/ZipArchive.java @@ -196,7 +196,7 @@ public final class ZipArchive extends PlainFile { // Private Class - FileEntry /** A regular file archive entry */ - private final class FileEntry extends Entry { + public final class FileEntry extends Entry { public final ZipEntry entry; -- cgit v1.2.3