diff --git a/build.sbt b/build.sbt index 09dce913..2d50c232 100644 --- a/build.sbt +++ b/build.sbt @@ -1,10 +1,12 @@ import ScalaModulePlugin._ import sbtcrossproject.{crossProject, CrossType} +resolvers in ThisBuild += "scala-pr" at "https://scala-ci.typesafe.com/artifactory/scala-pr-validation-snapshots/" + scalaVersionsByJvm in ThisBuild := { val v211 = "2.11.11" val v212 = "2.12.3" - val v213 = "2.13.0-M2" + val v213 = "2.13.0-pre-47ffa9c-SNAPSHOT" Map( 6 -> List(v211 -> true), @@ -23,7 +25,7 @@ lazy val `scala-parser-combinators` = crossProject(JSPlatform, JVMPlatform, Nati settings( name := "scala-parser-combinators", version := "1.0.7-SNAPSHOT", - mimaPreviousVersion := Some("1.0.5"), + mimaPreviousVersion := Some("1.0.6"), apiMappings += (scalaInstance.value.libraryJar -> url(s"https://www.scala-lang.org/api/${scalaVersion.value}/")), diff --git a/jvm/src/test/scala/scala/util/parsing/combinator/t4929.scala b/jvm/src/test/scala/scala/util/parsing/combinator/t4929.scala index 945bb283..f2672246 100644 --- a/jvm/src/test/scala/scala/util/parsing/combinator/t4929.scala +++ b/jvm/src/test/scala/scala/util/parsing/combinator/t4929.scala @@ -1,6 +1,6 @@ import scala.util.parsing.json._ import java.util.concurrent._ -import collection.JavaConversions._ +import collection.JavaConverters._ import org.junit.Test @@ -36,6 +36,6 @@ class t4929 { thread.setDaemon(true) thread.start() } - errors foreach { throw(_) } + errors.asScala foreach { throw(_) } } } diff --git a/shared/src/main/scala-2.13.0-pre-47ffa9c-SNAPSHOT/scala/collection/immutable/PagedSeq.scala b/shared/src/main/scala-2.13.0-pre-47ffa9c-SNAPSHOT/scala/collection/immutable/PagedSeq.scala new file mode 100644 index 00000000..1c7595a5 --- /dev/null +++ b/shared/src/main/scala-2.13.0-pre-47ffa9c-SNAPSHOT/scala/collection/immutable/PagedSeq.scala @@ -0,0 +1,275 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + + + +package scala +package collection +package immutable + +import java.io.{File, FileReader, Reader} +import scala.reflect.ClassTag + +/** The `PagedSeq` object defines a lazy implementations of + * a random access sequence. + * + * Provides utility methods that return instances of `PagedSeq[Char]`. + * `fromIterator` and `fromIterable` provide generalised instances of `PagedSeq` + */ +object PagedSeq { + final val UndeterminedEnd = Int.MaxValue + + /** Constructs a paged sequence from an iterator */ + def fromIterator[T: ClassTag](source: Iterator[T]): PagedSeq[T] = + new PagedSeq[T]((data: Array[T], start: Int, len: Int) => { + var i = 0 + while (i < len && source.hasNext) { + data(start + i) = source.next() + i += 1 + } + if (i == 0) -1 else i + }) + + /** Constructs a paged sequence from an iterable */ + def fromIterable[T: ClassTag](source: Iterable[T]): PagedSeq[T] = + fromIterator(source.iterator) + + /** Constructs a paged character sequence from a string iterator */ + def fromStrings(source: Iterator[String]): PagedSeq[Char] = { + var current: String = "" + def more(data: Array[Char], start: Int, len: Int): Int = + if (current.length != 0) { + val cnt = current.length min len + current.getChars(0, cnt, data, start) + current = current.substring(cnt) + if (cnt == len) cnt + else (more(data, start + cnt, len - cnt) max 0) + cnt + } else if (source.hasNext) { + current = source.next() + more(data, start, len) + } else -1 + new PagedSeq(more(_: Array[Char], _: Int, _: Int)) + } + + /** Constructs a paged character sequence from a string iterable */ + def fromStrings(source: Iterable[String]): PagedSeq[Char] = + fromStrings(source.iterator) + + /** Constructs a paged character sequence from a line iterator + * Lines do not contain trailing `\n` characters; The method inserts + * a line separator `\n` between any two lines in the sequence. + */ + def fromLines(source: Iterator[String]): PagedSeq[Char] = { + var isFirst = true + fromStrings(source map { line => + if (isFirst) { + isFirst = false + line + } else "\n"+line + }) + } + + /** Constructs a paged character sequence from a line iterable + * Lines do not contain trailing `\n` characters; The method inserts + * a line separator `\n` between any two lines in the sequence. + */ + def fromLines(source: Iterable[String]): PagedSeq[Char] = + fromLines(source.iterator) + + /** Constructs a paged character sequence from an input reader + */ + def fromReader(source: Reader): PagedSeq[Char] = + new PagedSeq(source.read(_: Array[Char], _: Int, _: Int)) + + /** Constructs a paged character sequence from an input file + */ + def fromFile(source: File): PagedSeq[Char] = + fromReader(new FileReader(source)) + + /** Constructs a paged character sequence from a file with given name + */ + def fromFile(source: String): PagedSeq[Char] = + fromFile(new File(source)) + + /** Constructs a paged character sequence from a scala.io.Source value + */ + def fromSource(source: scala.io.Source) = + fromLines(source.getLines()) +} + + +import PagedSeq._ + +/** An implementation of lazily computed sequences, where elements are stored + * in "pages", i.e. arrays of fixed size. + * + * A paged sequence is constructed from a function that produces more elements when asked. + * The producer function - `more`, is similar to the read method in java.io.Reader. + * The `more` function takes three parameters: an array of elements, a start index, and an end index. + * It should try to fill the array between start and end indices (excluding end index). + * It returns the number of elements produced, or -1 if end of logical input stream was reached + * before reading any element. + * + * @tparam T the type of the elements contained in this paged sequence, with an `ClassTag` context bound. + * + * @author Martin Odersky + * @define Coll `PagedSeq` + * @define coll paged sequence + * @define mayNotTerminateInf + * @define willNotTerminateInf + */ +class PagedSeq[T: ClassTag] protected( + more: (Array[T], Int, Int) => Int, + first1: Page[T], + start: Int, + end: Int) +extends collection.AbstractSeq[T] + with collection.IndexedSeq[T] +{ + def this(more: (Array[T], Int, Int) => Int) = this(more, new Page[T](0), 0, UndeterminedEnd) + + // Members declared in scala.collection.Seq + def iterableFactory: collection.SeqFactory[collection.IndexedSeq] = collection.IndexedSeq + + // Members declared in scala.collection.IterableOps + protected[this] def fromSpecificIterable(coll: collection.Iterable[T]): collection.IndexedSeq[T] = iterableFactory.from(coll) + protected[this] def newSpecificBuilder(): collection.mutable.Builder[T, collection.IndexedSeq[T]] = iterableFactory.newBuilder() + + private var current: Page[T] = first1 + + private def latest = first1.latest + + private def addMore() = latest.addMore(more) + + private def page(absindex: Int) = { + if (absindex < current.start) + current = first1 + while (absindex >= current.end && current.next != null) + current = current.next + while (absindex >= current.end && !current.isLast) { + current = addMore() + } + current + } + + /** The length of the paged sequence + * @note Calling this method will force the entire sequence to be read. + */ + def length: Int = { + while (!latest.isLast && latest.end < end) addMore() + (latest.end min end) - start + } + + /** The element at position `index`. + */ + def apply(index: Int) = + if (isDefinedAt(index)) page(index + start)(index + start) + else throw new IndexOutOfBoundsException(index.toString) + + /** Predicate method to check if an element is defined + * at position `index` of the current sequence. + * Unlike `length` this operation does not force reading + * a lazy sequence to the end. + */ + override def isDefinedAt(index: Int) = + index >= 0 && index < end - start && { + val absidx = index + start + absidx >= 0 && absidx < page(absidx).end + } + + /** The subsequence from index `start` up to `end -1` if `end` + * is lesser than the length of the current sequence and up to + * length of the sequence otherwise. This is limited up to the length + * of the current sequence if `end` is larger than its length. + */ + override def slice(_start: Int, _end: Int): PagedSeq[T] = { + page(start) + val s = start + _start + val e = if (_end == UndeterminedEnd) _end else start + _end + var f = first1 + while (f.end <= s && !f.isLast) { + if (f.next eq null) f = f.addMore(more) + else f = f.next + } + // Warning -- not refining `more` means that slices can freely request and obtain + // data outside of their slice. This is part of the design of PagedSeq + // (to read pages!) but can be surprising. + new PagedSeq(more, f, s, e) + } + + /** The subsequence from index `start` up to + * the length of the current sequence. + */ + def slice(start: Int): PagedSeq[T] = slice(start, UndeterminedEnd) + + /** Convert sequence to string */ + override def toString = { + val buf = new StringBuilder + for (ch <- PagedSeq.this.iterator) buf append ch + buf.toString + } +} + + +/** Page containing up to PageSize characters of the input sequence. + */ +private class Page[T: ClassTag](val num: Int) { + + private final val PageSize = 4096 + + /** The next page in the sequence */ + var next : Page[T] = null + + /** A later page in the sequence, serves a cache for pointing to last page */ + var later : Page[T] = this + + /** The number of elements read into this page */ + var filled: Int = 0 + + /** Set true if the current page is the last in the sequence or if + * the `more` function returned -1 signalling end of input. */ + var isLast: Boolean = false + + /** The element array */ + final val data = new Array[T](PageSize) + + /** The index of the first element in this page relative to the whole sequence */ + final def start = num * PageSize + + /** The index of the element following the last element in this page relative + * to the whole sequence */ + final def end = start + filled + + /** The last page as currently present in the sequence; This can change as more + * elements get appended to the sequence. */ + final def latest: Page[T] = { + if (later.next != null) later = later.next.latest + later + } + + /** The element at the given sequence index. + * That index is relative to the whole sequence, not the page. */ + def apply(index: Int) = { + if (index < start || index - start >= filled) throw new IndexOutOfBoundsException(index.toString) + data(index - start) + } + + /** Produces more elements by calling `more` and adds them on the current page, + * or fills a subsequent page if current page is full. + * @note If current page is full, it is the last one in the sequence. */ + final def addMore(more: (Array[T], Int, Int) => Int): Page[T] = + if (filled == PageSize) { + next = new Page[T](num + 1) + next.addMore(more) + } else { + val count = more(data, filled, PageSize - filled) + if (count < 0) isLast = true + else filled += count + this + } +} diff --git a/shared/src/main/scala/scala/util/parsing/json/JSON.scala b/shared/src/main/scala/scala/util/parsing/json/JSON.scala index 479ec021..43dfd9eb 100644 --- a/shared/src/main/scala/scala/util/parsing/json/JSON.scala +++ b/shared/src/main/scala/scala/util/parsing/json/JSON.scala @@ -73,8 +73,8 @@ object JSON extends Parser { * arrays. See the `parse` method for details. */ def resolveType(input: Any): Any = input match { - case JSONObject(data) => data.transform { - case (k,v) => resolveType(v) + case JSONObject(data) => data.map { + case (k,v) => k -> resolveType(v) } case JSONArray(data) => data.map(resolveType) case x => x diff --git a/shared/src/test/scala/scala/util/parsing/combinator/UnitTestIO.scala b/shared/src/test/scala/scala/util/parsing/combinator/UnitTestIO.scala index ffb6398e..82d7156f 100644 --- a/shared/src/test/scala/scala/util/parsing/combinator/UnitTestIO.scala +++ b/shared/src/test/scala/scala/util/parsing/combinator/UnitTestIO.scala @@ -26,7 +26,7 @@ class UnitTestIO { val s = "Here is a test string" val f = io.Source.fromBytes(s.getBytes("utf-8")) val b = new collection.mutable.ArrayBuffer[Char]() - f.copyToBuffer(b) + b ++= f assertEquals(new String(b.toArray), s) } } \ No newline at end of file