diff options
author | Martin Odersky <odersky@gmail.com> | 2009-01-13 18:50:50 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-01-13 18:50:50 +0000 |
commit | 323e895672ba0f9426be33de485bb7a6190af74c (patch) | |
tree | 97da75af4762b055dcd095ce84d2232af119ff12 | |
parent | 55795630fd0b7a4dd3e25dff1b9618e6f73adf23 (diff) | |
download | scala-323e895672ba0f9426be33de485bb7a6190af74c.tar.gz scala-323e895672ba0f9426be33de485bb7a6190af74c.tar.bz2 scala-323e895672ba0f9426be33de485bb7a6190af74c.zip |
renamed util.control.Break to Breaks and added ...
renamed util.control.Break to Breaks and added support for continue.
Fully implemented package objects.
14 files changed, 132 insertions, 71 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 6a41a36005..ba00802af7 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2360,8 +2360,11 @@ trait Parsers extends NewScanners with MarkupParsers { while (inToken != RBRACE && inToken != EOF) { if (inToken == PACKAGE) { val pkgPos = accept(PACKAGE) - stats += (if (inToken == OBJECT) objectDef(Modifiers(Flags.PACKAGE)) - else packaging(pkgPos)) + stats += { + if (inToken == OBJECT) + atPos(pkgPos) { makePackageObject(objectDef(NoMods)) } + else packaging(pkgPos) + } } else if (inToken == IMPORT) { stats ++= importClause() // XXX: IDE hook this all. @@ -2516,9 +2519,9 @@ trait Parsers extends NewScanners with MarkupParsers { // @S: just eat them (doesn't really change the grammar) while (inToken == SEMI) inNextToken if (inToken == PACKAGE) { - inNextToken + pos = inSkipToken if (in.token == OBJECT) { - ts += objectDef(Modifiers(Flags.PACKAGE)) + ts += makePackageObject(objectDef(NoMods)) if (inToken != EOF) { acceptStatSep() ts ++= topStatSeq() diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 4a4d05ebf5..c52e514119 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -453,5 +453,11 @@ abstract class TreeBuilder { makePackaging(qual, List(PackageDef(name, stats).setPos(pkg.pos))) } + /** Create a tree representing a package object */ + def makePackageObject(objDef: ModuleDef): PackageDef = objDef match { + case ModuleDef(mods, name, impl) => + makePackaging(Ident(name), List(ModuleDef(mods, nme.PACKAGEkw, impl))) + } + case class Parens(args: List[Tree]) extends Tree } diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index d64849c767..74a63b4e0c 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -118,13 +118,16 @@ abstract class SymbolLoaders { protected def newPackageLoader(dir: global.classPath0.Context): PackageLoader = new PackageLoader(dir) - protected def checkSource(name: String, source: AbstractFile): Boolean = true + protected def checkSource(name: String, source: AbstractFile): Boolean = source ne null var root: Symbol = _ def enterPackage(name: String, completer: SymbolLoader) { - if (inIDE && root.info.decls.lookup(newTermName(name)) != NoSymbol) { - return // refresh + val preExisting = root.info.decls.lookup(newTermName(name)) + if (preExisting != NoSymbol) { + if (inIDE) return + else throw new TypeError( + root+" contains object and package with same name: "+name+"\none of them needs to be removed from classpath") } val pkg = root.newPackage(NoPosition, newTermName(name)) pkg.moduleClass.setInfo(completer) @@ -158,44 +161,41 @@ abstract class SymbolLoaders { assert(root.isPackageClass, root) this.root = root root.setInfo(new PackageClassInfoType(scope, root, this)) - refresh + refresh() } - def refresh = { + def refresh() { /** Is the given name a valid input file base name? */ def isValid(name: String): Boolean = - name.length() > 0 && !name.endsWith("$class") && (/*settings.XO.value*/true || - (name.indexOf("$anon") == -1)); + name.length() > 0 && !name.endsWith("$class") + (/*settings.XO.value*/true || name.indexOf("$anon") == -1) val classes = new HashMap[String, global.classPath0.Context] val packages = new HashMap[String, global.classPath0.Context] + + def recordClass(file: AbstractFile, extension: String, classOK: global.classPath0.Context => Boolean) { + if (!file.isDirectory && file.name.endsWith(extension)) { + val name = file.name.substring(0, file.name.length - extension.length) + if (isValid(name) && !classes.isDefinedAt(name)) { + val clazz = directory.find(name, false) + if ((clazz ne null) && classOK(clazz)) classes(name) = clazz + } + } + } + for (dir <- directory.entries) if ((dir.location ne null) && (!inIDE || dir.location.isDirectory)) { for (file <- dir.location) { if (file.isDirectory && directory.validPackage(file.name) && !packages.isDefinedAt(file.name)) packages(file.name) = directory.find(file.name, true); - else if (!global.forMSIL && !file.isDirectory && file.name.endsWith(".class")) { - val name = file.name.substring(0, file.name.length() - (".class").length()); - if (isValid(name) && !classes.isDefinedAt(name)) { - val clazz = directory.find(name, false) - if (clazz ne null) classes(name) = clazz - } - } + else if (!global.forMSIL) + recordClass(file, ".class", source => true) } } for (dir <- directory.entries) if (dir.source ne null) { for (file <- dir.source.location) { if (file.isDirectory && directory.validPackage(file.name) && !packages.isDefinedAt(file.name)) packages(file.name) = directory.find(file.name, true) - else if (dir.source.compile && !file.isDirectory && file.name.endsWith(".scala")) { - val name = file.name.substring(0, file.name.length() - (".scala").length()) - if (isValid(name) && !classes.isDefinedAt(name)) { - val source = directory.find(name, false) - if ((source ne null) && (source.sourceFile ne null)) - if (checkSource(name, source.sourceFile)) - classes(name) = source - else if (settings.debug.value) - Console.println("Skipping source file " + source.sourceFile) - } - } + else if (dir.source.compile) + recordClass(file, ".scala", source => checkSource(name, source.sourceFile)) } } @@ -209,8 +209,20 @@ abstract class SymbolLoaders { } enterClassAndModule(name, loader) } + + // packages second for ((name, file) <- packages.elements) enterPackage(name, newPackageLoader(file)) + + // if there's a $member object, enter its members as well. + val membersModule = root.info.decl(nme.PACKAGEkw) + if (membersModule.isModule) { + for (member <- membersModule.info.decls.elements) { + // todo: handle overlapping definitions in some way: mark as errors + // or treat as abstractions. + root.info.decls.enter(member) + } + } } } @@ -230,8 +242,12 @@ abstract class SymbolLoaders { def namespace: String = if (root.isRoot) "" else root.fullNameString // TODO: Add check whether the source is newer than the assembly - override protected def checkSource(name: String, source: AbstractFile): Boolean = - !types.contains(name) + override protected def checkSource(name: String, source: AbstractFile): Boolean = { + val result = (source ne null) && !types.contains(name) + if (!result && settings.debug.value) + Console.println("Skipping source file " + source) + result + } override protected def doComplete(root: Symbol) { clrTypes.collectMembers(root, types, namespaces) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index a8062a8163..7009adb35d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -327,12 +327,6 @@ trait Infer { /** Check that <code>sym</code> is defined and accessible as a member of * tree <code>site</code> with type <code>pre</code> in current context. - * - * @param tree ... - * @param sym ... - * @param pre ... - * @param site ... - * @return ... */ def checkAccessible(tree: Tree, sym: Symbol, pre: Type, site: Tree): Tree = if (sym.isError) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index adab0faebf..f3fe615e80 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -181,13 +181,13 @@ trait Namers { self: Analyzer => } def enterPackageSymbol(pos: Position, name: Name): Symbol = { - val cscope = if (context.owner == EmptyPackageClass) RootClass.info.decls - else context.scope + val (cscope, cowner) = + if (context.owner == EmptyPackageClass) (RootClass.info.decls, RootClass) + else (context.scope, context.owner) val p: Symbol = cscope.lookupWithContext(name)(context.owner) if (p.isPackage && cscope == p.owner.info.decls) { p } else { - val cowner = if (context.owner == EmptyPackageClass) RootClass else context.owner val pkg = cowner.newPackage(pos, name) // IDE: newScope should be ok because packages are never destroyed. if (inIDE) assert(!pkg.moduleClass.hasRawInfo || !pkg.moduleClass.rawInfo.isComplete) @@ -286,7 +286,7 @@ trait Namers { self: Analyzer => def deSkolemize: TypeMap = new DeSkolemizeMap(applicableTypeParams(context.owner)) // should be special path for IDE but maybe not.... - def enterSym(tree: Tree): Context = { + def enterSym(tree: Tree): Context = try { def finishWith(tparams: List[TypeDef]) { val sym = tree.symbol @@ -399,6 +399,11 @@ trait Namers { self: Analyzer => } } this.context + } catch { + case ex: TypeError => + //Console.println("caught " + ex + " in enterSym")//DEBUG + typer.reportTypeError(tree.pos, ex) + this.context } def enterSyntheticSym(tree: Tree): Symbol = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 2c399b60d9..5a9ac741f6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -524,13 +524,40 @@ trait Typers { self: Analyzer => (mode & QUALmode) != 0 && !tree.symbol.isConstant || pt.typeSymbol.isAbstractType && pt.bounds.lo.isStable && !(tree.tpe <:< pt))) - /** <p> - * Post-process an identifier or selection node, performing the following: - * </p> - * <ol> - * <!--(1)--><li>Check that non-function pattern expressions are stable</li> - * <!--(2)--><li>Check that packages and static modules are not used as values</li> - * <!--(3)--><li>Turn tree type into stable type if possible and required by context.</li> + /** Make symbol accessible. This means: + * If symbol refers to package object, insert `.package` as second to last selector. + * Call checkAccessible, which sets symbol's attributes. + */ + private def makeAccessible(tree: Tree, sym: Symbol, pre: Type, site: Tree): Tree = + if (isInPackageObject(sym, pre.typeSymbol)) { + val qual = typedQualifier { + tree match { + case Ident(_) => Ident(nme.PACKAGEkw) + case Select(qual, _) => Select(qual, nme.PACKAGEkw) + case SelectFromTypeTree(qual, _) => Select(qual, nme.PACKAGEkw) + } + } + val tree1 = tree match { + case Ident(name) => Select(qual, name) + case Select(_, name) => Select(qual, name) + case SelectFromTypeTree(_, name) => SelectFromTypeTree(qual, name) + } + val tree2 = checkAccessible(tree1, sym, qual.tpe, qual) + tree2 + } else { + checkAccessible(tree, sym, pre, site) + } + + private def isInPackageObject(sym: Symbol, pkg: Symbol) = + pkg.isPackageClass && + sym.owner.isModuleClass && + sym.owner.name.toTermName == nme.PACKAGEkw && + sym.owner.owner == pkg + + /** Post-process an identifier or selection node, performing the following: + * 1. Check that non-function pattern expressions are stable + * 2. Check that packages and static modules are not used as values + * 3. Turn tree type into stable type if possible and required by context. * </ol> */ private def stabilize(tree: Tree, pre: Type, mode: Int, pt: Type): Tree = { @@ -2842,7 +2869,7 @@ trait Typers { self: Analyzer => case Select(_, _) => copy.Select(tree, qual, name) case SelectFromTypeTree(_, _) => copy.SelectFromTypeTree(tree, qual, name) } - val result = stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt) + val result = stabilize(makeAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt) if (phase.id <= currentRun.typerPhase.id && settings.Xchecknull.value && !sym.isConstructor && @@ -3014,7 +3041,7 @@ trait Typers { self: Analyzer => val tree1 = if (qual == EmptyTree) tree else atPos(tree.pos)(Select(qual, name)) // atPos necessary because qualifier might come from startContext - stabilize(checkAccessible(tree1, defSym, pre, qual), pre, mode, pt) + stabilize(makeAccessible(tree1, defSym, pre, qual), pre, mode, pt) } } diff --git a/src/library/scalax/collection/generic/IterableTemplate.scala b/src/library/scalax/collection/generic/IterableTemplate.scala index c48c8dfdf5..c2f1fadd9c 100755 --- a/src/library/scalax/collection/generic/IterableTemplate.scala +++ b/src/library/scalax/collection/generic/IterableTemplate.scala @@ -13,7 +13,7 @@ package scalax.collection.generic import scalax.collection.mutable.{Buffer, ArrayBuffer, ListBuffer} import scalax.collection.immutable.{List, Nil, ::, Stream} -import util.control.Break._ +import util.control.Breaks._ import Iterable._ /** Collection classes mixing in this class provide a method diff --git a/src/library/scalax/collection/generic/SequenceTemplate.scala b/src/library/scalax/collection/generic/SequenceTemplate.scala index 6cbe3e0fd6..27bba86ba0 100755 --- a/src/library/scalax/collection/generic/SequenceTemplate.scala +++ b/src/library/scalax/collection/generic/SequenceTemplate.scala @@ -11,7 +11,7 @@ package scalax.collection.generic -import util.control.Break._ +import util.control.Breaks._ import scalax.collection.immutable.{List, Nil, ::} import Sequence._ diff --git a/src/library/scalax/collection/generic/SequenceView.scala b/src/library/scalax/collection/generic/SequenceView.scala index 4cbf00b48d..72e863d4f2 100755 --- a/src/library/scalax/collection/generic/SequenceView.scala +++ b/src/library/scalax/collection/generic/SequenceView.scala @@ -11,7 +11,7 @@ package scalax.collection.generic -import util.control.Break._ +import util.control.Breaks._ import annotation.unchecked.uncheckedVariance import Sequence._ diff --git a/src/library/scalax/collection/generic/covartest/IterableTemplate.scala b/src/library/scalax/collection/generic/covartest/IterableTemplate.scala index bb5cc5e22d..27772b2ece 100755 --- a/src/library/scalax/collection/generic/covartest/IterableTemplate.scala +++ b/src/library/scalax/collection/generic/covartest/IterableTemplate.scala @@ -13,7 +13,7 @@ package scalax.collection.generic.covartest import scalax.collection.mutable.{Buffer, ArrayBuffer, ListBuffer} import scalax.collection.immutable.{List, Nil, ::, Stream} -import util.control.Break._ +import util.control.Breaks._ import Iterable._ /** Collection classes mixing in this class provide a method diff --git a/src/library/scalax/collection/generic/covartest/SequenceTemplate.scala b/src/library/scalax/collection/generic/covartest/SequenceTemplate.scala index c0f9dcf69f..eab7904af8 100755 --- a/src/library/scalax/collection/generic/covartest/SequenceTemplate.scala +++ b/src/library/scalax/collection/generic/covartest/SequenceTemplate.scala @@ -11,7 +11,7 @@ package scalax.collection.generic.covartest -import util.control.Break._ +import util.control.Breaks._ import scalax.collection.immutable.{List, Nil, ::} import Sequence._ diff --git a/src/library/scalax/collection/generic/covartest/SequenceView.scala b/src/library/scalax/collection/generic/covartest/SequenceView.scala index feb3c059ee..bae43636ae 100755 --- a/src/library/scalax/collection/generic/covartest/SequenceView.scala +++ b/src/library/scalax/collection/generic/covartest/SequenceView.scala @@ -11,7 +11,7 @@ package scalax.collection.generic.covartest -import util.control.Break._ +import util.control.Breaks._ import annotation.unchecked.uncheckedVariance import Sequence._ diff --git a/src/library/scalax/util/control/Break.scala b/src/library/scalax/util/control/Break.scala deleted file mode 100755 index 173188d2e9..0000000000 --- a/src/library/scalax/util/control/Break.scala +++ /dev/null @@ -1,15 +0,0 @@ -package scalax.util.control - -object Break { - private class BreakException extends RuntimeException - private val breakException = new BreakException - def break { throw breakException } - def breakable(op: => Unit) { - try { - op - } catch { - case ex: BreakException => - } - } -} - diff --git a/src/library/scalax/util/control/Breaks.scala b/src/library/scalax/util/control/Breaks.scala new file mode 100755 index 0000000000..d5ca883b77 --- /dev/null +++ b/src/library/scalax/util/control/Breaks.scala @@ -0,0 +1,25 @@ +package scalax.util.control + +object Breaks { + private class BreakException extends RuntimeException + private val breakException = new BreakException + private class ContinueException extends RuntimeException + private val continueException = new BreakException + def break { throw breakException } + def breakable(op: => Unit) { + try { + op + } catch { + case ex: BreakException => + } + } + def continue { throw continueException } + def continuable(op: => Unit) { + try { + op + } catch { + case ex: ContinueException => + continuable(op) + } + } +} |