diff options
author | Antonio Cunei <antonio.cunei@epfl.ch> | 2010-06-04 14:32:46 +0000 |
---|---|---|
committer | Antonio Cunei <antonio.cunei@epfl.ch> | 2010-06-04 14:32:46 +0000 |
commit | 38d7917431282455c493802599c79ca4647fcab4 (patch) | |
tree | 9144a911d44da15cea3c5fed568f6e2201d3603b /src | |
parent | 3d637ac989d965b8f76e4f4db2a61aa4a5d9a945 (diff) | |
download | scala-38d7917431282455c493802599c79ca4647fcab4.tar.gz scala-38d7917431282455c493802599c79ca4647fcab4.tar.bz2 scala-38d7917431282455c493802599c79ca4647fcab4.zip |
Merged revisions 22115,22154-22155,22157,22159-...
Merged revisions 22115,22154-22155,22157,22159-22161 via svnmerge from
https://lampsvn.epfl.ch/svn-repos/scala/scala/trunk
........
r22115 | extempore | 2010-06-01 19:44:33 +0200 (Tue, 01 Jun 2010) | 1 line
Make Iterator.toStream be properly lazy. Closes #3516, review by
prokopec. ........ r22154 | extempore | 2010-06-03 19:58:27 +0200 (Thu,
03 Jun 2010) | 6 lines
Restored Source factories to a form source compatible with 2.7.7. No
default implicit arguments, now low priority saves the day with a low
priority codec which io.Codec offers as last resort. Dropped the line
separator argument to getLines and made it act in a separator agnostic
way (any of \r\n, \r, or \n is a separator.) Review by community.
........ r22155 | extempore | 2010-06-03 20:55:18 +0200 (Thu, 03 Jun
2010) | 2 lines
Codec changes in scala.tools.nsc.io corresponding to those made in
r22154. No review. ........ r22157 | extempore | 2010-06-03 22:25:32
+0200 (Thu, 03 Jun 2010) | 3 lines
Sorted out some buck passing among TraversableOnce and its subclasses
about how exactly one creates a Stream. This is a continuation of r22115
for #3516. Review by prokopec. ........ r22159 | extempore | 2010-06-04
04:39:10 +0200 (Fri, 04 Jun 2010) | 4 lines
Reverts r21973, the patch I characterized as "hacky but no-risk" in
my commit message, for causing #3480. Closes #3480. I'd say no review
but who can trust a guy who throws around "no risk" with such abandon.
........ r22160 | extempore | 2010-06-04 07:03:51 +0200 (Fri, 04 Jun
2010) | 10 lines
Discovered and disproved this unlikely truth:
scala> (1 to 1 drop 1) == (1 to 1)
res0: Boolean = true
It was introduced in r21349 which was to fix #2535, but led to #3529.
I humbly suggest we can't afford to introduce bugs of this severity in
the pursuit of corner cases such as Ranges which use Int.MaxValue as a
boundary. And looking at the patch I find the "after" code a lot harder
to follow. Closes #3529. Review by prokopec. ........ r22161 | extempore
| 2010-06-04 07:16:08 +0200 (Fri, 04 Jun 2010) | 4 lines
Burned by a last minute adjustment, I lost the downward counting
direction. It is a seriously fiddly process to adjust Range and I don't
recommend it to anyone. Closes #3529 over again. Review by prokopec.
........
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/File.scala | 18 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/Streamable.scala | 45 | ||||
-rw-r--r-- | src/library/scala/LowPriorityImplicits.scala | 4 | ||||
-rw-r--r-- | src/library/scala/collection/Iterator.scala | 3 | ||||
-rw-r--r-- | src/library/scala/collection/TraversableLike.scala | 3 | ||||
-rw-r--r-- | src/library/scala/collection/TraversableOnce.scala | 23 | ||||
-rw-r--r-- | src/library/scala/collection/immutable/List.scala | 1 | ||||
-rw-r--r-- | src/library/scala/collection/immutable/Range.scala | 19 | ||||
-rw-r--r-- | src/library/scala/io/BufferedSource.scala | 6 | ||||
-rw-r--r-- | src/library/scala/io/Codec.scala | 22 | ||||
-rw-r--r-- | src/library/scala/io/Source.scala | 194 | ||||
-rw-r--r-- | src/library/scala/xml/parsing/ConstructingParser.scala | 5 | ||||
-rw-r--r-- | src/library/scala/xml/parsing/ExternalSources.scala | 5 | ||||
-rw-r--r-- | src/library/scala/xml/persistent/CachedFileStorage.scala | 2 |
15 files changed, 199 insertions, 154 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 |