aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-01-18 18:21:10 +0100
committerMartin Odersky <odersky@gmail.com>2014-01-18 18:21:23 +0100
commitf11dea6fc2eed56bee3eb1999c3890aae958e897 (patch)
treeefc124dc4151fddfae36b86689a24df12d9e2ec9 /tests
parentd172c1687eb4558369616696d93ed944f2fc8776 (diff)
downloaddotty-f11dea6fc2eed56bee3eb1999c3890aae958e897.tar.gz
dotty-f11dea6fc2eed56bee3eb1999c3890aae958e897.tar.bz2
dotty-f11dea6fc2eed56bee3eb1999c3890aae958e897.zip
Fix to computation of implicit scopes
For packages, the implicit scope consists of the implicit definitions in a nested `package` object, not the package itself.
Diffstat (limited to 'tests')
-rw-r--r--tests/pos/dotctest.scala259
1 files changed, 148 insertions, 111 deletions
diff --git a/tests/pos/dotctest.scala b/tests/pos/dotctest.scala
index 4e1eb224a..42efc7e06 100644
--- a/tests/pos/dotctest.scala
+++ b/tests/pos/dotctest.scala
@@ -1,135 +1,172 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2012 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+
package dotty.tools
-package dotc
-package util
-
-import scala.collection.mutable.ArrayBuffer
-import dotty.tools.io._
-import annotation.tailrec
-import java.util.regex.Pattern
-import java.io.IOException
-import Chars._
-import ScriptSourceFile._
-import Positions._
-
-object ScriptSourceFile {
- private val headerPattern = Pattern.compile("""^(::)?!#.*(\r|\n|\r\n)""", Pattern.MULTILINE)
- private val headerStarts = List("#!", "::#!")
-
- def apply(file: AbstractFile, content: Array[Char]) = {
- /** Length of the script header from the given content, if there is one.
- * The header begins with "#!" or "::#!" and ends with a line starting
- * with "!#" or "::!#".
- */
- val headerLength =
- if (headerStarts exists (content startsWith _)) {
- val matcher = headerPattern matcher content.mkString
- if (matcher.find) matcher.end
- else throw new IOException("script file does not close its header with !# or ::!#")
- } else 0
- new SourceFile(file, content drop headerLength) {
- override val underlying = new SourceFile(file, content)
- }
+package io
+
+import java.io.{ InputStream, OutputStream, IOException, FileNotFoundException, FileInputStream, DataOutputStream }
+import java.util.jar._
+import scala.collection.JavaConverters._
+import Attributes.Name
+import scala.language.{postfixOps, implicitConversions}
+
+// Attributes.Name instances:
+//
+// static Attributes.Name CLASS_PATH
+// static Attributes.Name CONTENT_TYPE
+// static Attributes.Name EXTENSION_INSTALLATION
+// static Attributes.Name EXTENSION_LIST
+// static Attributes.Name EXTENSION_NAME
+// static Attributes.Name IMPLEMENTATION_TITLE
+// static Attributes.Name IMPLEMENTATION_URL
+// static Attributes.Name IMPLEMENTATION_VENDOR
+// static Attributes.Name IMPLEMENTATION_VENDOR_ID
+// static Attributes.Name IMPLEMENTATION_VERSION
+// static Attributes.Name MAIN_CLASS
+// static Attributes.Name MANIFEST_VERSION
+// static Attributes.Name SEALED
+// static Attributes.Name SIGNATURE_VERSION
+// static Attributes.Name SPECIFICATION_TITLE
+// static Attributes.Name SPECIFICATION_VENDOR
+// static Attributes.Name SPECIFICATION_VERSION
+
+class Jar(file: File) extends Iterable[JarEntry] {
+ def this(jfile: JFile) = this(File(jfile))
+ def this(path: String) = this(File(path))
+
+ protected def errorFn(msg: String): Unit = Console println msg
+
+ lazy val jarFile = new JarFile(file.jfile)
+ lazy val manifest = withJarInput(s => Option(s.getManifest))
+
+ def mainClass = manifest map (f => f(Name.MAIN_CLASS))
+ /** The manifest-defined classpath String if available. */
+ def classPathString: Option[String] =
+ for (m <- manifest ; cp <- m.attrs get Name.CLASS_PATH) yield cp
+ def classPathElements: List[String] = classPathString match {
+ case Some(s) => s split "\\s+" toList
+ case _ => Nil
}
-}
-case class SourceFile(file: AbstractFile, content: Array[Char]) {
-
- def this(_file: AbstractFile) = this(_file, _file.toCharArray)
- def this(sourceName: String, cs: Seq[Char]) = this(new VirtualFile(sourceName), cs.toArray)
- def this(file: AbstractFile, cs: Seq[Char]) = this(file, cs.toArray)
+ def withJarInput[T](f: JarInputStream => T): T = {
+ val in = new JarInputStream(file.inputStream())
+ try f(in)
+ finally in.close()
+ }
+ def jarWriter(mainAttrs: (Attributes.Name, String)*) = {
+ new JarWriter(file, Jar.WManifest(mainAttrs: _*).underlying)
+ }
- /** Tab increment; can be overridden */
- def tabInc = 8
+ override def foreach[U](f: JarEntry => U): Unit = withJarInput { in =>
+ Iterator continually in.getNextJarEntry() takeWhile (_ != null) foreach f
+ }
+ override def iterator: Iterator[JarEntry] = this.toList.iterator
+ def fileishIterator: Iterator[Fileish] = jarFile.entries.asScala map (x => Fileish(x, () => getEntryStream(x)))
- override def equals(that : Any) = that match {
- case that : SourceFile => file.path == that.file.path && start == that.start
- case _ => false
+ private def getEntryStream(entry: JarEntry) = jarFile getInputStream entry match {
+ case null => errorFn("No such entry: " + entry) ; null
+ case x => x
}
- override def hashCode = file.path.## + start.##
+ override def toString = "" + file
+}
- def apply(idx: Int) = content.apply(idx)
+class JarWriter(val file: File, val manifest: Manifest) {
+ private lazy val out = new JarOutputStream(file.outputStream(), manifest)
- val length = content.length
+ /** Adds a jar entry for the given path and returns an output
+ * stream to which the data should immediately be written.
+ * This unusual interface exists to work with fjbg.
+ */
+ def newOutputStream(path: String): DataOutputStream = {
+ val entry = new JarEntry(path)
+ out putNextEntry entry
+ new DataOutputStream(out)
+ }
- /** true for all source files except `NoSource` */
- def exists: Boolean = true
+ def writeAllFrom(dir: Directory): Unit = {
+ try dir.list foreach (x => addEntry(x, ""))
+ finally out.close()
+ }
+ def addStream(entry: JarEntry, in: InputStream): Unit = {
+ out putNextEntry entry
+ try transfer(in, out)
+ finally out.closeEntry()
+ }
+ def addFile(file: File, prefix: String): Unit = {
+ val entry = new JarEntry(prefix + file.name)
+ addStream(entry, file.inputStream())
+ }
+ def addEntry(entry: Path, prefix: String): Unit = {
+ if (entry.isFile) addFile(entry.toFile, prefix)
+ else addDirectory(entry.toDirectory, prefix + entry.name + "/")
+ }
+ def addDirectory(entry: Directory, prefix: String): Unit = {
+ entry.list foreach (p => addEntry(p, prefix))
+ }
- /** The underlying source file */
- def underlying: SourceFile = this
+ private def transfer(in: InputStream, out: OutputStream) = {
+ val buf = new Array[Byte](10240)
+ def loop(): Unit = in.read(buf, 0, buf.length) match {
+ case -1 => in.close()
+ case n => out.write(buf, 0, n) ; loop
+ }
+ loop
+ }
- /** The start of this file in the underlying source file */
- def start = 0
+ def close() = out.close()
+}
- def atPos(pos: Position): SourcePosition =
- if (pos.exists) SourcePosition(underlying, pos)
- else NoSourcePosition
+object Jar {
+ type AttributeMap = java.util.Map[Attributes.Name, String]
- def isSelfContained = underlying eq this
+ object WManifest {
+ def apply(mainAttrs: (Attributes.Name, String)*): WManifest = {
+ val m = WManifest(new JManifest)
+ for ((k, v) <- mainAttrs)
+ m(k) = v
- /** Map a position to a position in the underlying source file.
- * For regular source files, simply return the argument.
- */
- def positionInUltimateSource(position: SourcePosition): SourcePosition =
- SourcePosition(underlying, position.pos shift start)
-
- def isLineBreak(idx: Int) =
- if (idx >= length) false else {
- val ch = content(idx)
- // don't identify the CR in CR LF as a line break, since LF will do.
- if (ch == CR) (idx + 1 == length) || (content(idx + 1) != LF)
- else isLineBreakChar(ch)
+ m
}
-
- def calculateLineIndices(cs: Array[Char]) = {
- val buf = new ArrayBuffer[Int]
- buf += 0
- for (i <- 0 until cs.length) if (isLineBreak(i)) buf += i + 1
- buf += cs.length // sentinel, so that findLine below works smoother
- buf.toArray
+ def apply(manifest: JManifest): WManifest = new WManifest(manifest)
+ implicit def unenrichManifest(x: WManifest): JManifest = x.underlying
}
- private lazy val lineIndices: Array[Int] = calculateLineIndices(content)
-
- /** Map line to offset of first character in line */
- def lineToOffset(index : Int): Int = lineIndices(index)
+ class WManifest(manifest: JManifest) {
+ for ((k, v) <- initialMainAttrs)
+ this(k) = v
+
+ def underlying = manifest
+ def attrs = manifest.getMainAttributes().asInstanceOf[AttributeMap].asScala withDefaultValue null
+ def initialMainAttrs: Map[Attributes.Name, String] = {
+ import scala.util.Properties._
+ Map(
+ Name.MANIFEST_VERSION -> "1.0",
+ ScalaCompilerVersion -> versionNumberString
+ )
+ }
- /** A cache to speed up offsetToLine searches to similar lines */
- private var lastLine = 0
+ def apply(name: Attributes.Name): String = attrs(name)
+ def apply(name: String): String = apply(new Attributes.Name(name))
+ def update(key: Attributes.Name, value: String) = attrs.put(key, value)
+ def update(key: String, value: String) = attrs.put(new Attributes.Name(key), value)
- /** Convert offset to line in this source file
- * Lines are numbered from 0
- */
- def offsetToLine(offset: Int): Int = {
- val lines = lineIndices
- def findLine(lo: Int, hi: Int, mid: Int): Int =
- if (offset < lines(mid)) findLine(lo, mid - 1, (lo + mid - 1) / 2)
- else if (offset >= lines(mid + 1)) findLine(mid + 1, hi, (mid + 1 + hi) / 2)
- else mid
- lastLine = findLine(0, lines.length, lastLine)
- lastLine
+ def mainClass: String = apply(Name.MAIN_CLASS)
+ def mainClass_=(value: String) = update(Name.MAIN_CLASS, value)
}
- def startOfLine(offset: Int): Int = lineToOffset(offsetToLine(offset))
-
- def nextLine(offset: Int): Int =
- lineToOffset(offsetToLine(offset) + 1 min lineIndices.length - 1)
+ // See http://download.java.net/jdk7/docs/api/java/nio/file/Path.html
+ // for some ideas.
+ private val ZipMagicNumber = List[Byte](80, 75, 3, 4)
+ private def magicNumberIsZip(f: Path) = f.isFile && (f.toFile.bytes().take(4).toList == ZipMagicNumber)
- def lineContents(offset: Int): String =
- content.slice(startOfLine(offset), nextLine(offset)).mkString
+ def isJarOrZip(f: Path): Boolean = isJarOrZip(f, true)
+ def isJarOrZip(f: Path, examineFile: Boolean): Boolean =
+ f.hasExtension("zip", "jar") || (examineFile && magicNumberIsZip(f))
- def column(offset: Int): Int = {
- var idx = startOfLine(offset)
- var col = 0
- while (idx != offset) {
- col += (if (content(idx) == '\t') tabInc - col % tabInc else 1)
- idx += 1
- }
- col + 1
+ def create(file: File, sourceDir: Directory, mainClass: String): Unit = {
+ val writer = new Jar(file).jarWriter(Name.MAIN_CLASS -> mainClass)
+ writer writeAllFrom sourceDir
}
-
- override def toString = file.toString
}
-
-object NoSource extends SourceFile("<no source>", Nil) {
- override def exists = false
-}
-