diff --git a/src/main/scala/scala/util/parsing/input/StreamReader.scala b/src/main/scala/scala/util/parsing/input/StreamReader.scala index 384ecf0c..1883187d 100644 --- a/src/main/scala/scala/util/parsing/input/StreamReader.scala +++ b/src/main/scala/scala/util/parsing/input/StreamReader.scala @@ -45,27 +45,29 @@ object StreamReader { * @author Miles Sabin * @author Martin Odersky */ -sealed class StreamReader(seq: PagedSeq[Char], off: Int, lnum: Int) extends PagedSeqReader(seq, off) { - import StreamReader._ +sealed class StreamReader private (seq: PagedSeq[Char], off: Int, lnum: Int, nextEol0: Int) extends PagedSeqReader(seq, off) { + def this(seq: PagedSeq[Char], off: Int, lnum: Int) = this(seq, off, lnum, -1) + + import StreamReader.EofCh override def rest: StreamReader = - if (off == seq.length) this + if (!seq.isDefinedAt(off)) this else if (seq(off) == '\n') - new StreamReader(seq.slice(off + 1), 0, lnum + 1) - else new StreamReader(seq, off + 1, lnum) + new StreamReader(seq.slice(off + 1), 0, lnum + 1, -1) + else new StreamReader(seq, off + 1, lnum, nextEol0) - private def nextEol = { + private def nextEol = if (nextEol0 == -1) { var i = off - while (i < seq.length && seq(i) != '\n' && seq(i) != EofCh) i += 1 + while (seq.isDefinedAt(i) && seq(i) != '\n' && seq(i) != EofCh) i += 1 i - } + } else nextEol0 override def drop(n: Int): StreamReader = { val eolPos = nextEol - if (eolPos < off + n && eolPos < seq.length) - new StreamReader(seq.slice(eolPos + 1), 0, lnum + 1).drop(off + n - (eolPos + 1)) + if (eolPos < off + n && seq.isDefinedAt(eolPos)) + new StreamReader(seq.slice(eolPos + 1), 0, lnum + 1, -1).drop(off + n - (eolPos + 1)) else - new StreamReader(seq, off + n, lnum) + new StreamReader(seq, off + n, lnum, eolPos) } override def pos: Position = new Position { diff --git a/src/test/scala/scala/util/parsing/combinator/t8879.scala b/src/test/scala/scala/util/parsing/combinator/t8879.scala new file mode 100644 index 00000000..2be5a563 --- /dev/null +++ b/src/test/scala/scala/util/parsing/combinator/t8879.scala @@ -0,0 +1,42 @@ +import scala.util.parsing.input._ +import scala.collection.immutable.PagedSeq + +import org.junit.Test +import org.junit.Assert.fail + +class t8879 { + + @Test + def test: Unit = { + val testPagedSeq = { + var nbpage = 0 + def more(data: Array[Char], start: Int, len: Int): Int = { + if (nbpage < 1) { + var i = 0 + while (i < len && nbpage < 3) { + if (i % 100 != 0) { + data(start + i) = 'a' + } else { + data(start + i) = '\n' + } + i += 1 + } + if (i == 0) -1 else { + nbpage += 1 + i + } + } else { + fail("Should not read more than 1 page!") + 0 + } + } + + new PagedSeq(more(_: Array[Char], _: Int, _: Int)) + } + + val s = new StreamReader(testPagedSeq, 0, 1) + + // should not trigger reading of the second page + s.drop(20) + } +}