summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala3
-rw-r--r--src/compiler/scala/tools/nsc/io/File.scala18
-rw-r--r--src/compiler/scala/tools/nsc/io/Streamable.scala45
-rw-r--r--src/library/scala/LowPriorityImplicits.scala4
-rw-r--r--src/library/scala/collection/Iterator.scala3
-rw-r--r--src/library/scala/collection/TraversableLike.scala3
-rw-r--r--src/library/scala/collection/TraversableOnce.scala23
-rw-r--r--src/library/scala/collection/immutable/List.scala1
-rw-r--r--src/library/scala/collection/immutable/Range.scala19
-rw-r--r--src/library/scala/io/BufferedSource.scala6
-rw-r--r--src/library/scala/io/Codec.scala22
-rw-r--r--src/library/scala/io/Source.scala194
-rw-r--r--src/library/scala/xml/parsing/ConstructingParser.scala5
-rw-r--r--src/library/scala/xml/parsing/ExternalSources.scala5
-rw-r--r--src/library/scala/xml/persistent/CachedFileStorage.scala2
-rw-r--r--test/files/jvm/unittest_io.scala2
-rw-r--r--test/files/pos/bug3480.scala4
-rw-r--r--test/files/run/bug3516.check3
-rw-r--r--test/files/run/bug3516.scala13
-rw-r--r--test/files/run/bug3529.scala14
-rw-r--r--test/pending/neg/bug3189.check (renamed from test/files/neg/bug3189.check)0
-rw-r--r--test/pending/neg/bug3189.scala (renamed from test/files/neg/bug3189.scala)0
22 files changed, 234 insertions, 155 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index 182ae6c21c..0bfee7cdd8 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1547,7 +1547,8 @@ self =>
var top = simplePattern(seqOK)
// See ticket #3189 for the motivation for the null check.
// TODO: dredge out the remnants of regexp patterns.
- if (seqOK && isIdent && in.name == STAR && in.prev.name != null)
+ // ... and now this is back the way it was because it caused #3480.
+ if (seqOK && isIdent && in.name == STAR)
return atPos(top.pos.startOrPoint, in.skipToken())(Star(stripParens(top)))
while (isIdent && in.name != BAR) {
diff --git a/src/compiler/scala/tools/nsc/io/File.scala b/src/compiler/scala/tools/nsc/io/File.scala
index fb7170b3b3..d8e1410375 100644
--- a/src/compiler/scala/tools/nsc/io/File.scala
+++ b/src/compiler/scala/tools/nsc/io/File.scala
@@ -20,9 +20,7 @@ object File {
def pathSeparator = JFile.pathSeparator
def separator = JFile.separator
- def apply(path: Path)(implicit codec: Codec = null) =
- if (codec != null) new File(path.jfile)(codec)
- else path.toFile
+ def apply(path: Path)(implicit codec: Codec) = new File(path.jfile)(codec)
// Create a temporary file
def makeTemp(prefix: String = Path.randomPrefix, suffix: String = null, dir: JFile = null) =
@@ -56,10 +54,10 @@ import Path._
* @author Paul Phillips
* @since 2.8
*/
-class File(jfile: JFile)(implicit val creationCodec: Codec = null)
-extends Path(jfile)
-with Streamable.Chars {
+class File(jfile: JFile)(implicit constructorCodec: Codec) extends Path(jfile) with Streamable.Chars {
+ override val creationCodec = constructorCodec
def withCodec(codec: Codec): File = new File(jfile)(codec)
+
override def addExtension(ext: String): File = super.addExtension(ext).toFile
override def toAbsolute: File = if (isAbsolute) this else super.toAbsolute.toFile
override def toDirectory: Directory = new Directory(jfile)
@@ -82,12 +80,16 @@ with Streamable.Chars {
* This should behave like a less broken version of java.io.FileWriter,
* in that unlike the java version you can specify the encoding.
*/
- def writer(append: Boolean = false, codec: Codec = getCodec()) =
+ def writer(): OutputStreamWriter = writer(false)
+ def writer(append: Boolean): OutputStreamWriter = writer(append, creationCodec)
+ def writer(append: Boolean, codec: Codec): OutputStreamWriter =
new OutputStreamWriter(outputStream(append), codec.charSet)
/** Wraps a BufferedWriter around the result of writer().
*/
- def bufferedWriter(append: Boolean = false, codec: Codec = getCodec()) =
+ def bufferedWriter(): BufferedWriter = bufferedWriter(false)
+ def bufferedWriter(append: Boolean): BufferedWriter = bufferedWriter(append, creationCodec)
+ def bufferedWriter(append: Boolean, codec: Codec): BufferedWriter =
new BufferedWriter(writer(append, codec))
/** Creates a new file and writes all the Strings to it. */
diff --git a/src/compiler/scala/tools/nsc/io/Streamable.scala b/src/compiler/scala/tools/nsc/io/Streamable.scala
index ff4520e3ca..16a867ade8 100644
--- a/src/compiler/scala/tools/nsc/io/Streamable.scala
+++ b/src/compiler/scala/tools/nsc/io/Streamable.scala
@@ -8,7 +8,7 @@ package io
import java.net.{ URI, URL }
import java.io.{ BufferedInputStream, InputStream, PrintStream, File => JFile }
import java.io.{ BufferedReader, InputStreamReader }
-import scala.io.{ Codec, Source }
+import scala.io.{ Codec, BufferedSource, Source }
import collection.mutable.ArrayBuffer
import Path.fail
@@ -66,40 +66,32 @@ object Streamable
}
}
- /** For objects which can be viewed as Chars. The abstract creationCodec
- * can safely be defined as null and will subsequently be ignored.
+ /** For objects which can be viewed as Chars.
*/
trait Chars extends Bytes {
- def creationCodec: Codec
- private def failNoCodec() = fail("This method requires a Codec to be chosen explicitly.")
-
- /** The general algorithm for any call to a method involving byte<->char
- * transformations is: if a codec is supplied (explicitly or implicitly),
- * use that; otherwise if a codec was defined when the object was created,
- * use that; otherwise, use Codec.default.
- *
- * Note that getCodec takes a codec argument rather than having methods
- * always default to getCodec() and use the argument otherwise, so that
- * method implementations can, where desired, identify the case where no
- * codec was ever explicitly supplied. If allowDefault = false, an
- * exception will be thrown rather than falling back on Codec.default.
+ /** Calls to methods requiring byte<->char transformations should be offered
+ * in a form which allows specifying the codec. When it is not specified,
+ * the one discovered at creation time will be used, which will always find the
+ * one in scala.io.Codec if no other is available. This can be overridden
+ * to use a different default.
*/
- def getCodec(givenCodec: Codec = null, allowDefault: Boolean = true) =
- if (givenCodec != null) givenCodec
- else if (creationCodec != null) creationCodec
- else if (allowDefault) Codec.default
- else failNoCodec()
+ def creationCodec: Codec = implicitly[Codec]
- def chars(codec: Codec = getCodec()): Source = (Source fromInputStream inputStream())(codec)
- def lines(codec: Codec = getCodec()): Iterator[String] = chars(codec).getLines()
+ def chars(): BufferedSource = chars(creationCodec)
+ def chars(codec: Codec): BufferedSource = Source.fromInputStream(inputStream())(codec)
+
+ def lines(): Iterator[String] = lines(creationCodec)
+ def lines(codec: Codec): Iterator[String] = chars(codec).getLines()
/** Obtains an InputStreamReader wrapped around a FileInputStream.
*/
- def reader(codec: Codec = getCodec()) = new InputStreamReader(inputStream, codec.charSet)
+ def reader(): InputStreamReader = reader(creationCodec)
+ def reader(codec: Codec): InputStreamReader = new InputStreamReader(inputStream, codec.charSet)
/** Wraps a BufferedReader around the result of reader().
*/
- def bufferedReader(codec: Codec = getCodec()) = new BufferedReader(reader(codec))
+ def bufferedReader(): BufferedReader = bufferedReader(creationCodec)
+ def bufferedReader(codec: Codec) = new BufferedReader(reader(codec))
/** Creates a BufferedReader and applies the closure, automatically closing it on completion.
*/
@@ -111,6 +103,7 @@ object Streamable
/** Convenience function to import entire file into a String.
*/
- def slurp(codec: Codec = getCodec()) = chars(codec).mkString
+ def slurp(): String = slurp(creationCodec)
+ def slurp(codec: Codec) = chars(codec).mkString
}
}
diff --git a/src/library/scala/LowPriorityImplicits.scala b/src/library/scala/LowPriorityImplicits.scala
index 6fdf977dd4..32bdf7e30d 100644
--- a/src/library/scala/LowPriorityImplicits.scala
+++ b/src/library/scala/LowPriorityImplicits.scala
@@ -6,8 +6,6 @@
** |/ **
\* */
-
-
package scala
import collection.mutable._
@@ -59,6 +57,4 @@ class LowPriorityImplicits {
def wrapArray(xs: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(xs)
def wrapArray(xs: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(xs)
def wrapArray(xs: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(xs)
-
-
}
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index daa6a59f3b..b8dd03110d 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -1007,6 +1007,9 @@ trait Iterator[+A] extends TraversableOnce[A] {
def toTraversable: Traversable[A] = toStream
def toIterator: Iterator[A] = self
+ def toStream: Stream[A] =
+ if (self.hasNext) Stream.cons(self.next, self.toStream)
+ else Stream.empty[A]
/** Converts this iterator to a string.
* @return `"empty iterator"` or `"non-empty iterator"`, depending on whether or not the iterator is empty.
diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala
index 50259a1ee8..71e9b0f0e9 100644
--- a/src/library/scala/collection/TraversableLike.scala
+++ b/src/library/scala/collection/TraversableLike.scala
@@ -694,7 +694,8 @@ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] with Traversable
}
def toTraversable: Traversable[A] = thisCollection
- def toIterator: Iterator[A] = toIterable.iterator
+ def toIterator: Iterator[A] = toStream.iterator
+ def toStream: Stream[A] = Stream.empty[A] ++ thisCollection
/** Converts this $coll to a string.
* @return a string representation of this collection. By default this
diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala
index 3984264168..5d09b6d2c6 100644
--- a/src/library/scala/collection/TraversableOnce.scala
+++ b/src/library/scala/collection/TraversableOnce.scala
@@ -66,6 +66,12 @@ trait TraversableOnce[+A] {
*/
def toTraversable: Traversable[A]
+ /** Converts this $coll to a stream.
+ * $willNotTerminateInf
+ * @return a stream containing all elements of this $coll.
+ */
+ def toStream: Stream[A]
+
/** Presently these are abstract because the Traversable versions use
* breakable/break, and I wasn't sure enough of how that's supposed to
* function to consolidate them with the Iterator versions.
@@ -383,7 +389,7 @@ trait TraversableOnce[+A] {
copyToArray(result, 0)
result
}
- else toStream.toArray
+ else toBuffer.toArray
}
/** Converts this $coll to a list.
@@ -392,17 +398,20 @@ trait TraversableOnce[+A] {
*/
def toList: List[A] = new ListBuffer[A] ++= self toList
- /** Converts this $coll to an iterable collection.
+ /** Converts this $coll to an iterable collection. Note that
+ * the choice of target Iterable must be lazy as this TraversableOnce
+ * may be lazy and unevaluated.
+ *
* $willNotTerminateInf
* @return an `Iterable` containing all elements of this $coll.
*/
def toIterable: Iterable[A] = toStream
- /** Converts this $coll to a sequence.
+ /** Converts this $coll to a sequence. As with toIterable, it must be lazy.
* $willNotTerminateInf
* @return a sequence containing all elements of this $coll.
*/
- def toSeq: Seq[A] = toList
+ def toSeq: Seq[A] = toStream
/** Converts this $coll to an indexed sequence.
* $willNotTerminateInf
@@ -416,12 +425,6 @@ trait TraversableOnce[+A] {
*/
def toBuffer[B >: A]: mutable.Buffer[B] = new ArrayBuffer[B] ++= self
- /** Converts this $coll to a stream.
- * $willNotTerminateInf
- * @return a stream containing all elements of this $coll.
- */
- def toStream: Stream[A] = toList.toStream
-
/** Converts this $coll to a set.
* $willNotTerminateInf
* @return a set containing all elements of this $coll.
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index 26d5948f2c..7785d73175 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -244,7 +244,6 @@ sealed abstract class List[+A] extends LinearSeq[A]
if (isEmpty) Stream.Empty
else new Stream.Cons(head, tail.toStream)
-
/** Like <code>span</code> but with the predicate inverted.
*/
@deprecated("use `span { x => !p(x) }` instead")
diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala
index cef043555f..68b50fd09f 100644
--- a/src/library/scala/collection/immutable/Range.scala
+++ b/src/library/scala/collection/immutable/Range.scala
@@ -87,6 +87,9 @@ class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int]
}
// take and drop have to be tolerant of large values without overflowing
+ // warning! this is buggy, and gives wrong answers on boundary cases.
+ // The known bugs are avoided by drop not calling it in those cases.
+ // See ticket #3529. It should be revised.
private def locationAfterN(n: Int) = if (n > 0) {
if (step > 0)
((start.toLong + step.toLong * n.toLong) min last.toLong).toInt
@@ -103,11 +106,11 @@ class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int]
* @param n the number of elements to take.
* @return a new range consisting of `n` first elements.
*/
- final override def take(n: Int): Range = if (n > 0 && length > 0) {
- Range(start, locationAfterN(n - 1), step).inclusive
- } else {
- Range(start, start, step)
- }
+ final override def take(n: Int): Range =
+ if (n > 0 && length > 0)
+ Range(start, locationAfterN(n - 1), step).inclusive
+ else
+ Range(start, start, step)
/** Creates a new range containing all the elements of this range except the first `n` elements.
*
@@ -117,7 +120,11 @@ class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int]
* @return a new range consisting of all the elements of this range except `n` first elements.
*/
final override def drop(n: Int): Range =
- copy(locationAfterN(n), end, step)
+ if (n >= length) {
+ if (step > 0) copy(end + 1, end, step)
+ else copy(end - 1, end, step)
+ }
+ else copy(locationAfterN(n), end, step)
/** Creates a new range containing all the elements of this range except the last one.
*
diff --git a/src/library/scala/io/BufferedSource.scala b/src/library/scala/io/BufferedSource.scala
index b4e0389e12..f0230d3724 100644
--- a/src/library/scala/io/BufferedSource.scala
+++ b/src/library/scala/io/BufferedSource.scala
@@ -18,10 +18,10 @@ import Source.DefaultBufSize
*
* @author Burak Emir, Paul Phillips
*/
-class BufferedSource(inputStream: InputStream)(implicit codec: Codec = Codec.default) extends Source
-{
+class BufferedSource(inputStream: InputStream, bufferSize: Int)(implicit val codec: Codec) extends Source {
+ def this(inputStream: InputStream)(implicit codec: Codec) = this(inputStream, DefaultBufSize)(codec)
def reader() = new InputStreamReader(inputStream, codec.decoder)
- def bufferedReader() = new BufferedReader(reader(), DefaultBufSize)
+ def bufferedReader() = new BufferedReader(reader(), bufferSize)
override val iter = {
val reader = bufferedReader()
diff --git a/src/library/scala/io/Codec.scala b/src/library/scala/io/Codec.scala
index 2b74c67134..e001e732c2 100644
--- a/src/library/scala/io/Codec.scala
+++ b/src/library/scala/io/Codec.scala
@@ -25,8 +25,7 @@ import java.nio.charset.{ Charset, CharsetDecoder, CharsetEncoder, CharacterCodi
/** A class for character encoding/decoding preferences.
*
*/
-class Codec(val charSet: Charset)
-{
+class Codec(val charSet: Charset) {
type Configure[T] = (T => T, Boolean)
type Handler = CharacterCodingException => Int
@@ -70,11 +69,26 @@ class Codec(val charSet: Charset)
})
}
-object Codec {
+trait LowPriorityCodecImplicits {
+ self: Codec.type =>
+
+ /** The Codec of Last Resort. */
+ implicit def fallbackSystemCodec: Codec = defaultCharsetCodec
+}
+
+object Codec extends LowPriorityCodecImplicits {
final val ISO8859 = Charset forName "ISO-8859-1"
final val UTF8 = Charset forName "UTF-8"
- def default = apply(Charset.defaultCharset)
+ /** Optimistically these two possible defaults will be the same thing.
+ * In practice this is not necessarily true, and in fact Sun classifies
+ * the fact that you can influence anything at all via -Dfile.encoding
+ * as an accident, with any anomalies considered "not a bug".
+ */
+ def defaultCharsetCodec = apply(Charset.defaultCharset)
+ def fileEncodingCodec = apply(util.Properties.encodingString)
+ def default = defaultCharsetCodec
+
def apply(encoding: String): Codec = new Codec(Charset forName encoding)
def apply(charSet: Charset): Codec = new Codec(charSet)
def apply(decoder: CharsetDecoder): Codec = {
diff --git a/src/library/scala/io/Source.scala b/src/library/scala/io/Source.scala
index 5b279d720c..b5313ef61b 100644
--- a/src/library/scala/io/Source.scala
+++ b/src/library/scala/io/Source.scala
@@ -26,36 +26,78 @@ object Source {
*/
def stdin = fromInputStream(System.in)
- /** Creates a <code>Source</code> from an Iterable.
+ /** Creates a Source from an Iterable.
*
* @param iterable the Iterable
- * @return the <code>Source</code> instance.
+ * @return the Source
*/
def fromIterable(iterable: Iterable[Char]): Source = new Source {
val iter = iterable.iterator
} withReset(() => fromIterable(iterable))
- /** Creates a <code>Source</code> instance from a single character.
- *
- * @param c ...
- * @return the create <code>Source</code> instance.
+ /** Creates a Source instance from a single character.
*/
def fromChar(c: Char): Source = fromIterable(Array(c))
/** creates Source from array of characters, with empty description.
- *
- * @param chars ...
- * @return ...
*/
def fromChars(chars: Array[Char]): Source = fromIterable(chars)
- /** creates Source from string, with empty description.
- *
- * @param s ...
- * @return ...
+ /** creates Source from a String, with no description.
*/
def fromString(s: String): Source = fromIterable(s)
+ /** creates Source from file with given name, setting its description to
+ * filename.
+ */
+ def fromFile(name: String)(implicit codec: Codec): BufferedSource =
+ fromFile(new JFile(name))(codec)
+
+ /** creates Source from file with given name, using given encoding, setting
+ * its description to filename.
+ */
+ def fromFile(name: String, enc: String): BufferedSource =
+ fromFile(name)(Codec(enc))
+
+ /** creates <code>Source</code> from file with given file: URI
+ */
+ def fromFile(uri: URI)(implicit codec: Codec): BufferedSource =
+ fromFile(new JFile(uri))(codec)
+
+ /** creates Source from file with given file: URI
+ */
+ def fromFile(uri: URI, enc: String): BufferedSource =
+ fromFile(uri)(Codec(enc))
+
+ /** creates Source from file, using default character encoding, setting its
+ * description to filename.
+ */
+ def fromFile(file: JFile)(implicit codec: Codec): BufferedSource =
+ fromFile(file, Source.DefaultBufSize)(codec)
+
+ /** same as fromFile(file, enc, Source.DefaultBufSize)
+ */
+ def fromFile(file: JFile, enc: String): BufferedSource =
+ fromFile(file)(Codec(enc))
+
+ def fromFile(file: JFile, enc: String, bufferSize: Int): BufferedSource =
+ fromFile(file, bufferSize)(Codec(enc))
+
+ /** Creates Source from <code>file</code>, using given character encoding,
+ * setting its description to filename. Input is buffered in a buffer of
+ * size <code>bufferSize</code>.
+ */
+ def fromFile(file: JFile, bufferSize: Int)(implicit codec: Codec): BufferedSource = {
+ val inputStream = new FileInputStream(file)
+
+ createBufferedSource(
+ inputStream,
+ bufferSize,
+ () => fromFile(file, bufferSize)(codec),
+ () => inputStream.close()
+ )(codec) withDescription ("file:" + file.getAbsolutePath)
+ }
+
/** Create a <code>Source</code> from array of bytes, decoding
* the bytes according to codec.
*
@@ -63,74 +105,69 @@ object Source {
* @param enc ...
* @return the created <code>Source</code> instance.
*/
- def fromBytes(bytes: Array[Byte])(implicit codec: Codec = Codec.default): Source =
+ def fromBytes(bytes: Array[Byte])(implicit codec: Codec): Source =
fromString(new String(bytes, codec.name))
+ def fromBytes(bytes: Array[Byte], enc: String): Source =
+ fromBytes(bytes)(Codec(enc))
+
/** Create a <code>Source</code> from array of bytes, assuming
* one byte per character (ISO-8859-1 encoding.)
*/
def fromRawBytes(bytes: Array[Byte]): Source = fromString(new String(bytes, Codec.ISO8859.name))
- /** creates Source from file with given name, setting
- * its description to filename.
+ /** creates <code>Source</code> from file with given file: URI
*/
- def fromPath(name: String)(implicit codec: Codec = Codec.default): Source = fromFile(new JFile(name))
+ def fromURI(uri: URI)(implicit codec: Codec): BufferedSource = fromFile(new JFile(uri))(codec)
- /** creates <code>Source</code> from file with given file: URI
+ /** same as fromURL(new URL(s))(Codec(enc))
*/
- def fromURI(uri: URI)(implicit codec: Codec = Codec.default): Source = fromFile(new JFile(uri))
+ def fromURL(s: String, enc: String): BufferedSource =
+ fromURL(s)(Codec(enc))
- /** same as fromInputStream(url.openStream())(codec)
+ /** same as fromURL(new URL(s))
*/
- def fromURL(url: URL)(implicit codec: Codec = Codec.default): Source =
- fromInputStream(url.openStream())(codec)
+ def fromURL(s: String)(implicit codec: Codec): BufferedSource =
+ fromURL(new URL(s))(codec)
- /** Creates Source from <code>file</code>, using given character encoding,
- * setting its description to filename. Input is buffered in a buffer of
- * size <code>bufferSize</code>.
+ /** same as fromInputStream(url.openStream())(Codec(enc))
*/
- def fromFile(file: JFile, bufferSize: Int = DefaultBufSize)(implicit codec: Codec = Codec.default): Source = {
- val inputStream = new FileInputStream(file)
+ def fromURL(url: URL, enc: String): BufferedSource =
+ fromURL(url)(Codec(enc))
- fromInputStream(
- inputStream,
- bufferSize,
- () => fromFile(file, bufferSize)(codec),
- () => inputStream.close()
- ) withDescription ("file:" + file.getAbsolutePath)
- }
+ /** same as fromInputStream(url.openStream())(codec)
+ */
+ def fromURL(url: URL)(implicit codec: Codec): BufferedSource =
+ fromInputStream(url.openStream())(codec)
- /** Reads data from <code>inputStream</code> with a buffered reader,
- * using encoding in implicit parameter <code>codec</code>.
+ /** Reads data from inputStream with a buffered reader, using the encoding
+ * in implicit parameter codec.
*
* @param inputStream the input stream from which to read
* @param bufferSize buffer size (defaults to Source.DefaultBufSize)
* @param reset a () => Source which resets the stream (if unset, reset() will throw an Exception)
+ * @param close a () => Unit method which closes the stream (if unset, close() will do nothing)
* @param codec (implicit) a scala.io.Codec specifying behavior (defaults to Codec.default)
* @return the buffered source
*/
- def fromInputStream(
+ def createBufferedSource(
inputStream: InputStream,
bufferSize: Int = DefaultBufSize,
reset: () => Source = null,
close: () => Unit = null
- )(implicit codec: Codec = Codec.default): Source =
- {
+ )(implicit codec: Codec): BufferedSource = {
// workaround for default arguments being unable to refer to other parameters
- val resetFn = if (reset == null) () => fromInputStream(inputStream, bufferSize, reset, close) else reset
- new BufferedSource(inputStream)(codec) .
- withReset (resetFn) .
- withClose (close)
+ val resetFn = if (reset == null) () => createBufferedSource(inputStream, bufferSize, reset, close)(codec) else reset
+
+ new BufferedSource(inputStream, bufferSize)(codec) withReset resetFn withClose close
}
-}
-// Coming Soon?
-//
-// abstract class Source2[T] extends Iterable[T] { }
-//
-// abstract class ByteSource() extends Source2[Byte] { }
-//
-// abstract class CharSource(implicit codec: Codec = Codec.default) extends Source2[Char] { }
+ def fromInputStream(is: InputStream, enc: String): BufferedSource =
+ fromInputStream(is)(Codec(enc))
+
+ def fromInputStream(is: InputStream)(implicit codec: Codec): BufferedSource =
+ createBufferedSource(is, reset = () => fromInputStream(is)(codec), close = () => is.close())(codec)
+}
/** The class <code>Source</code> implements an iterable representation
* of source data. Calling method <code>reset</code> returns an identical,
@@ -139,8 +176,7 @@ object Source {
* @author Burak Emir
* @version 1.0
*/
-abstract class Source extends Iterator[Char]
-{
+abstract class Source extends Iterator[Char] {
/** the actual iterator */
protected val iter: Iterator[Char]
@@ -152,42 +188,35 @@ abstract class Source extends Iterator[Char]
var nerrors = 0
var nwarnings = 0
- /** convenience method, returns given line (not including newline)
+ /** Convenience method, returns given line (not including newline)
* from Source.
*
* @param line the line index, first line is 1
- * @return the character string of the specified line.
+ * @return the specified line.
*
*/
+ @deprecated("Use a collections method such as getLines().toIndexedSeq for random access.")
def getLine(line: Int): String = getLines() drop (line - 1) next
- class LineIterator(separator: String) extends Iterator[String] {
- require(separator.length == 1 || separator.length == 2, "Line separator may be 1 or 2 characters only.")
- lazy val iter: BufferedIterator[Char] = Source.this.iter.buffered
- // For two character newline sequences like \r\n, we peek at
- // the iterator head after seeing \r, and drop the \n if present.
- val isNewline: Char => Boolean = {
- val firstCh = separator(0)
- if (separator.length == 1) (_ == firstCh)
- else (ch: Char) => (ch == firstCh) && iter.hasNext && {
- val res = iter.head == separator(1)
- if (res) { iter.next } // drop the second character
- res
- }
- }
+ class LineIterator() extends Iterator[String] {
private[this] val sb = new StringBuilder
- private def getc() =
- if (!iter.hasNext) false
+ lazy val iter: BufferedIterator[Char] = Source.this.iter.buffered
+ def isNewline(ch: Char) = ch == '\r' || ch == '\n'
+ def getc() = iter.hasNext && {
+ val ch = iter.next
+ if (ch == '\n') false
+ else if (ch == '\r') {
+ if (iter.hasNext && iter.head == '\n')
+ iter.next
+
+ false
+ }
else {
- val ch = iter.next
- if (isNewline(ch)) false
- else {
- sb append ch
- true
- }
+ sb append ch
+ true
}
-
+ }
def hasNext = iter.hasNext
def next = {
sb.clear
@@ -196,12 +225,11 @@ abstract class Source extends Iterator[Char]
}
}
- /** returns an iterator who returns lines (NOT including newline character(s)).
- * If no separator is given, the platform-specific value "line.separator" is used.
- * a line ends in \r, \n, or \r\n.
+ /** Returns an iterator who returns lines (NOT including newline character(s)).
+ * It will treat any of \r\n, \r, or \n as a line separator (longest match) - if
+ * you need more refined behavior you can subclass Source#LineIterator directly.
*/
- def getLines(separator: String = compat.Platform.EOL): Iterator[String] =
- new LineIterator(separator)
+ def getLines(): Iterator[String] = new LineIterator()
/** Returns <code>true</code> if this source has more characters.
*/
diff --git a/src/library/scala/xml/parsing/ConstructingParser.scala b/src/library/scala/xml/parsing/ConstructingParser.scala
index e54e411587..b5a8f0ba25 100644
--- a/src/library/scala/xml/parsing/ConstructingParser.scala
+++ b/src/library/scala/xml/parsing/ConstructingParser.scala
@@ -12,12 +12,11 @@ package scala.xml
package parsing
import java.io.File
-
-import scala.io.{ Source, Codec }
+import scala.io.Source
object ConstructingParser {
def fromFile(inp: File, preserveWS: Boolean) =
- new ConstructingParser(Source.fromFile(inp)(), preserveWS) initialize
+ new ConstructingParser(Source.fromFile(inp), preserveWS) initialize
def fromSource(inp: Source, preserveWS: Boolean) =
new ConstructingParser(inp, preserveWS) initialize
diff --git a/src/library/scala/xml/parsing/ExternalSources.scala b/src/library/scala/xml/parsing/ExternalSources.scala
index e0a0f6b986..a1363b8b17 100644
--- a/src/library/scala/xml/parsing/ExternalSources.scala
+++ b/src/library/scala/xml/parsing/ExternalSources.scala
@@ -20,8 +20,7 @@ import scala.io.Source
* @author Burak Emir
* @version 1.0
*/
-trait ExternalSources
-{
+trait ExternalSources {
self: ExternalSources with MarkupParser with MarkupHandler =>
/** ...
@@ -38,6 +37,6 @@ trait ExternalSources
case x => x take ((x lastIndexOf separator) + 1)
}
- Source.fromPath(fileStr + systemId)()
+ Source.fromFile(fileStr + systemId)
}
}
diff --git a/src/library/scala/xml/persistent/CachedFileStorage.scala b/src/library/scala/xml/persistent/CachedFileStorage.scala
index dfd675f36a..5550259a09 100644
--- a/src/library/scala/xml/persistent/CachedFileStorage.scala
+++ b/src/library/scala/xml/persistent/CachedFileStorage.scala
@@ -73,7 +73,7 @@ extends java.lang.Thread with scala.util.logging.Logged {
import scala.io.Source
import scala.xml.parsing.ConstructingParser
log("[load]\nloading "+theFile)
- val src = Source.fromFile(theFile)()
+ val src = Source.fromFile(theFile)
log("parsing "+theFile)
val res = ConstructingParser.fromSource(src,false).document.docElem(0)
switch
diff --git a/test/files/jvm/unittest_io.scala b/test/files/jvm/unittest_io.scala
index 80d33d8433..fd5889cb86 100644
--- a/test/files/jvm/unittest_io.scala
+++ b/test/files/jvm/unittest_io.scala
@@ -15,7 +15,7 @@ it is split on several lines.
isn't it?
""")
- def runTest() = assertEquals("wrong number of lines",src.getLines("\n").toList.length,5) // five new lines in there
+ def runTest() = assertEquals("wrong number of lines",src.getLines.toList.length,5) // five new lines in there
//for (line <- src.getLines) {
// Console.print(line)
//}
diff --git a/test/files/pos/bug3480.scala b/test/files/pos/bug3480.scala
new file mode 100644
index 0000000000..830365170b
--- /dev/null
+++ b/test/files/pos/bug3480.scala
@@ -0,0 +1,4 @@
+object Test {
+ val List(_*) = List(1)
+ val Array( who, what @ _* ) = "Eclipse plugin cannot not handle this" split (" ")
+}
diff --git a/test/files/run/bug3516.check b/test/files/run/bug3516.check
new file mode 100644
index 0000000000..d0d10d82fa
--- /dev/null
+++ b/test/files/run/bug3516.check
@@ -0,0 +1,3 @@
+1
+1
+21
diff --git a/test/files/run/bug3516.scala b/test/files/run/bug3516.scala
new file mode 100644
index 0000000000..aa302ce85a
--- /dev/null
+++ b/test/files/run/bug3516.scala
@@ -0,0 +1,13 @@
+object Test {
+ def mkIterator = (1 to 5).iterator map (x => { println(x) ; x })
+ def mkInfinite = Iterator continually { println(1) ; 1 }
+
+ def main(args: Array[String]): Unit = {
+ // Stream is strict in its head so we should see 1 from each of them.
+ val s1 = mkIterator.toStream
+ val s2 = mkInfinite.toStream
+ // back and forth without slipping into nontermination.
+ println((Stream from 1).toIterator.drop(10).toStream.drop(10).toIterator.next)
+ ()
+ }
+}
diff --git a/test/files/run/bug3529.scala b/test/files/run/bug3529.scala
new file mode 100644
index 0000000000..bb82424bf6
--- /dev/null
+++ b/test/files/run/bug3529.scala
@@ -0,0 +1,14 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ assert(1 to 10 drop 10 isEmpty)
+ assert(1 until 10 drop 9 isEmpty)
+ assert(1 to 10 by 2 drop 5 isEmpty)
+ assert(10 to 1 by -1 drop 10 isEmpty)
+ assert((10 to 1 by -1 drop 9) == Seq(1))
+
+ assert((1 to 10 drop 9) == Seq(10))
+ assert((1 until 10 drop 9) == Nil)
+
+ assert(Stream(1 to 10).flatten.toList == Stream(1 until 11).flatten.toList)
+ }
+}
diff --git a/test/files/neg/bug3189.check b/test/pending/neg/bug3189.check
index 520644fd43..520644fd43 100644
--- a/test/files/neg/bug3189.check
+++ b/test/pending/neg/bug3189.check
diff --git a/test/files/neg/bug3189.scala b/test/pending/neg/bug3189.scala
index 4ea4bb7581..4ea4bb7581 100644
--- a/test/files/neg/bug3189.scala
+++ b/test/pending/neg/bug3189.scala