summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala2
-rwxr-xr-xsrc/compiler/scala/tools/nsc/typechecker/DeVirtualize.txt56
-rwxr-xr-xsrc/library/scala/CharSequence.scala155
-rw-r--r--src/library/scala/Enumeration.scala2
-rw-r--r--src/library/scala/LazyCharSequence.scala265
-rw-r--r--src/library/scala/Predef.scala3
-rw-r--r--src/library/scala/Stream.scala13
-rw-r--r--src/library/scala/collection/jcl/Map.scala2
-rw-r--r--src/library/scala/collection/jcl/MutableIterable.scala2
-rw-r--r--src/library/scala/runtime/RichString.scala7
-rwxr-xr-xsrc/library/scala/runtime/StreamCons.scala17
-rw-r--r--src/library/scala/util/matching/Regex.scala304
-rw-r--r--src/library/scala/util/parsing/combinator/JavaTokenParsers.scala24
-rwxr-xr-xsrc/library/scala/util/parsing/combinator/RegexParsers.scala51
-rw-r--r--src/library/scala/util/parsing/combinator/lexical/Scanners.scala4
-rw-r--r--src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala4
-rw-r--r--src/library/scala/util/parsing/input/CharArrayPosition.scala4
-rw-r--r--src/library/scala/util/parsing/input/CharArrayReader.scala6
-rwxr-xr-xsrc/library/scala/util/parsing/input/CharArraySequence.scala37
-rwxr-xr-xsrc/library/scala/util/parsing/input/CharSequenceReader.scala28
-rw-r--r--src/library/scala/util/parsing/input/NoPosition.scala2
-rwxr-xr-xsrc/library/scala/util/parsing/input/OffsetPosition.scala4
-rw-r--r--src/library/scala/util/parsing/input/Position.scala4
-rw-r--r--src/library/scala/util/parsing/input/Reader.scala17
-rwxr-xr-xsrc/library/scala/util/parsing/input/StreamReader.scala49
-rwxr-xr-xtest/partestall8
-rwxr-xr-xtest/partestall.bat7
27 files changed, 840 insertions, 237 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index e76be5a09d..aa5131a445 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -229,7 +229,7 @@ trait Definitions {
}).normalize
/* </unapply> */
- val MaxFunctionArity = 9
+ val MaxFunctionArity = 22
val FunctionClass: Array[Symbol] = new Array(MaxFunctionArity + 1)
def functionApply(n: Int) = getMember(FunctionClass(n), nme.apply)
def functionType(formals: List[Type], restpe: Type) =
diff --git a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.txt b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.txt
new file mode 100755
index 0000000000..4ca1317d5e
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.txt
@@ -0,0 +1,56 @@
+ /*
+ class A {
+ class C[X, Y](x: X) <: { var y = x ; def f(z: Y): X }
+ class D[Y](z) extends C[Int, Y](f(z)) { override def f(z:Int) = 3 }
+ }
+ class B extends A {
+ class C[X, Y](x: X) <: { def g = 2 }
+ }
+ */
+
+ class A {
+ type C[X, Y] <: CT[X, Y]
+
+ trait CT { self: C => protected[this] val x: Int; val y = x; def f(z:Int) = z + 1 }
+
+ type D <: C with DT
+
+ trait DT extends { self: D => def f(z:Int) = z + 2 }
+
+ trait preDT extends { self: D => val z: Int; val x = f(z) }
+
+ def newC(x: Int): C
+ def newD(x: Int): D
+
+ //type C = CT
+ //type D = C with DT
+
+ class CC(_x:Int) extends { val x = _x } with CT
+
+ def newC(x:Int): C = new CC(x).asInstanceOf[C]
+
+ class DC(_z:Int) extends { val z = _z } with preDT with CT with DT {
+ override def f(z:Int) = super.f(z)
+ }
+
+ def newD(z:Int):D = new DC(z).asInstanceOf[D]
+ }
+
+ class B extends A {
+ type C <: CT with CT2
+
+ trait CT2 { self : C => def g = 2 }
+
+ //type C = CT with CT2
+ //type D = C with DT
+
+ class CC2(_x:Int) extends { val x = _x } with CT with CT2
+
+ def newC(x:Int): C = new CC2(x).asInstanceOf[C]
+
+ class DC2(_z:Int) extends { val z = _z } with preDT with CT with CT2
+ with DT { override def f(z:Int) = super.f(z) }
+
+ def newD(z:Int): D = new DC2(z).asInstanceOf[D]
+ }
+
diff --git a/src/library/scala/CharSequence.scala b/src/library/scala/CharSequence.scala
new file mode 100755
index 0000000000..da776256a6
--- /dev/null
+++ b/src/library/scala/CharSequence.scala
@@ -0,0 +1,155 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id:
+
+
+package scala
+
+import java.io._
+import collection._
+import util.matching.Regex
+
+/** A Scala abstraction of character sequences, similar to, but richer than,
+ * java.lang.CharSequence. Sequences can be fixed or lazy. A lazy
+ * character sequence may be constructed only while it is read.
+ *
+ * @author Martin Odersky
+ */
+trait CharSequence extends java.lang.CharSequence with Seq[Char] {
+
+ /** The length of the character sequence
+ * Note: if char sequence is lazy, calling this method
+ * will force sequence to be read until the end.
+ */
+ def length: Int
+
+ /** The character at position `index'.
+ */
+ def charAt(index: Int): Char
+
+ /** Is character sequence defined at `index'?
+ * Unlike `length' this operation does not force reading
+ * a lazy sequence to the end.
+ * (the implementation of that method is inherited from Seq).
+ */
+ def isDefinedAt(index: Int): Boolean
+
+ /** Optionally the character at position `index'. None is not in range.
+ */
+ def get(index: Int): Option[Char] =
+ if (isDefinedAt(index)) Some(charAt(index))
+ else None
+
+ /** The character at position `index'. (same as `charAt')
+ */
+ def apply(index: Int): Char = charAt(index)
+
+ /** the subsequence from index `start' up to and excluding
+ * the minimum of index `end' and the length of current sequence.
+ */
+ def subSequence(start: Int, end: Int): CharSequence
+
+ /** The subsequence from index `start' until the end of the current sequence
+ * If sequence is lazy, this operation does not force reading to the end.
+ */
+ def subSequence(start: Int): CharSequence =
+ subSequence(start, length)
+
+ /** Convert sequence to string */
+ def toString: String
+
+ /** the elements of this sequence */
+ def elements: Iterator[Char] = new Iterator[Char] {
+ private var index = 0
+ def hasNext: Boolean = isDefinedAt(index)
+ def next: Char = {
+ val ch = charAt(index)
+ index += 1
+ ch
+ }
+ }
+
+ /** Return all matches of given regexp in this character sequence as an iterator
+ */
+ def findAll(regex: Regex): Regex.MatchIterator = regex findAllIn this
+
+ /** Return first match of given regexp in this character sequence as an optional value
+ */
+ def findFirst(regex: Regex): Option[String] = regex findFirstIn this
+
+ /** Return first match of given regexp in this character sequence as an optional value
+ */
+ def findFirstMatch(regex: Regex): Option[Regex.Match] = regex findFirstMatchIn this
+
+ /** Return optionally string matching given regexp at the beginning of this
+ * character sequence, or None if regexp matches no prefix
+ * of the character sequence.
+ */
+ def findPrefix(regex: Regex): Option[String] = regex findPrefixOf this
+
+ /** Return optionally match for given regexp at the beginning of this
+ * character sequence, or None if regexp matches no prefix
+ * of the character sequence.
+ */
+ def findPrefixMatch(regex: Regex): Option[Regex.Match] = regex findPrefixMatchOf this
+
+ /** Replaces all matches of given regexp by a string.
+ *
+ * @param regex The regex to match with
+ * @param replacement The string that will replace each match
+ * @return The resulting string
+ */
+ def replaceAll(regex: Regex, replacement: String): String = regex replaceAllIn (this, replacement)
+
+ /** Replaces the first match of given regexp by a string.
+ *
+ * @param target The string to match
+ * @param replacement The string that will replace the match
+ * @return The resulting string
+ */
+ def replaceFirst(regex: Regex, replacement: String): String = regex replaceFirstIn (this, replacement)
+}
+
+/** The CharSequence object defines variance implementations of character sequences
+ */
+object CharSequence {
+
+ def fromJava(source: java.lang.CharSequence): CharSequence =
+ new JavaWrapper(source)
+
+ def fromArray(source: Array[Char]): CharSequence =
+ new AsArray(source, 0, source.length)
+ def fromArray(source: Array[Char], start: Int): CharSequence =
+ new AsArray(source, start, source.length)
+ def fromArray(source: Array[Char], start: Int, end: Int): CharSequence =
+ new AsArray(source, start, end)
+
+ private class JavaWrapper(source: java.lang.CharSequence) extends CharSequence {
+ def length: Int = source.length
+ def charAt(index: Int): Char = source.charAt(index)
+ def subSequence(start: Int, end: Int): CharSequence = new JavaWrapper(source.subSequence(start, end))
+ override def toString: String = source.toString
+ }
+
+ private class AsArray(source: scala.Array[Char], start: Int, end: Int) extends CharSequence {
+ if (start < 0) throw new IndexOutOfBoundsException
+ if (end > source.length) throw new IndexOutOfBoundsException
+
+ def charAt(index: Int) =
+ if (start + index < end) source(index + start)
+ else throw new IndexOutOfBoundsException
+
+ def length: Int = if (end < start) 0 else end - start
+
+ def subSequence(_start: Int, _end: Int) =
+ new AsArray(source, start + _start, start + _end)
+
+ override def toString = new String(source, start, end - start)
+ }
+}
diff --git a/src/library/scala/Enumeration.scala b/src/library/scala/Enumeration.scala
index 9c91996d23..93ed320f64 100644
--- a/src/library/scala/Enumeration.scala
+++ b/src/library/scala/Enumeration.scala
@@ -310,7 +310,7 @@ abstract class Enumeration(initial: Int, names: String*) {
}
}
def contains(value : Value) = (underlying & value.mask32) != 0
- def |( set : Set32) = new Set32(underlying | set.underlying)
+ def |(set : Set32) = new Set32(underlying | set.underlying)
def |(value : Value) = new Set32(underlying | value.mask32)
def &~(value : Value) = new Set32(underlying & (~value.mask32))
def &(set : Set32) = new Set32(underlying & set.underlying)
diff --git a/src/library/scala/LazyCharSequence.scala b/src/library/scala/LazyCharSequence.scala
new file mode 100644
index 0000000000..6f773b817c
--- /dev/null
+++ b/src/library/scala/LazyCharSequence.scala
@@ -0,0 +1,265 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id:
+
+
+package scala
+
+import java.io._
+import util.matching.Regex
+
+
+/** The CharSequence object defines variance implementations of character sequences
+ */
+object LazyCharSequence {
+ final val UndeterminedEnd = Math.MAX_INT
+
+ /** Constructs a character sequence from a character iterator */
+ def fromChars(source: Iterator[Char]): CharSequence =
+ new LazyCharSequence ((chars: Array[Char], start: Int, len: Int) => {
+ var i = 0
+ while (i < len && source.hasNext) {
+ chars(start + i) = source.next
+ i += 1
+ }
+ if (i == 0) -1 else i
+ })
+
+ /** Constructs a character sequence from a character iterable */
+ def fromChars(source: Iterable[Char]): CharSequence =
+ fromChars(source.elements)
+
+ /** Constructs a character sequence from a string iterator */
+ def fromStrings(source: Iterator[String]): CharSequence = {
+ var current: String = ""
+ def more(chars: Array[Char], start: Int, len: Int): Int =
+ if (current.length != 0) {
+ val nchars = current.length min len
+ current.getChars(0, nchars, chars, start)
+ current = current.substring(nchars)
+ if (nchars == len) nchars
+ else (more(chars, start + nchars, len - nchars) max 0) + nchars
+ } else if (source.hasNext) {
+ current = source.next
+ more(chars, start, len)
+ } else -1
+ new LazyCharSequence(more(_: Array[Char], _: Int, _: Int))
+ }
+
+ /** Constructs a character sequence from a string iterable */
+ def fromStrings(source: Iterable[String]): CharSequence =
+ fromStrings(source.elements)
+
+ /** Constructs a 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]): CharSequence = {
+ var isFirst = true
+ fromStrings(source map { line =>
+ if (isFirst) line
+ else {
+ isFirst = false
+ "\n"+line
+ }
+ })
+ }
+
+ /** Constructs a 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]): CharSequence =
+ fromLines(source.elements)
+
+ /** Constructs a character sequence from an input reader
+ */
+ def fromReader(source: Reader): CharSequence =
+ new LazyCharSequence(source)
+
+ /** Constructs a character sequence from an input file
+ */
+ def fromFile(source: File) =
+ new LazyCharSequence(source)
+
+ /** Constructs a character sequence from a file with given name
+ */
+ def fromFile(source: String) =
+ new LazyCharSequence(source)
+
+ /** Constructs a character sequence from a scala.io.Source value
+ */
+ def fromSource(source: io.Source) =
+ fromLines(source.getLines)
+}
+
+
+import LazyCharSequence._
+
+/** An implementation of lazily computed character sequences
+ *
+ * @author Martin Odersky
+ */
+class LazyCharSequence protected (more: (Array[Char], Int, Int) => Int,
+ first: Page, start: Int, end: Int) extends CharSequence {
+
+ /** Constructs a character sequence from a method that produces more characters when asked.
+ * The producer method is analogous to the read method in java.io.Reader.
+ * It takes three parameters: an array of characters, a start index, and an end index.
+ * It should try to fill the array between start and end indices (not including end index).
+ * It returns the number of characters produced, or -1 if end of logical input stream was reached
+ * before any character was read.
+ */
+ def this(more: (Array[Char], Int, Int) => Int) = this(more, new Page(0), 0, UndeterminedEnd)
+
+ /** Constructs a character sequence from an input reader
+ */
+ def this(source: Reader) =
+ this(source.read(_: Array[Char], _: Int, _: Int))
+
+ /** Constructs a character sequence from an input file
+ */
+ def this(source: File) =
+ this(new FileReader(source))
+
+ /** Constructs a character sequence from a file with given name
+ */
+ def this(source: String) =
+ this(new File(source))
+
+ private var current: Page = first
+
+ private def latest = first.latest
+
+ private def addMore() = latest.addMore(more)
+
+ private def page(absindex: Int) = {
+ if (absindex < current.start)
+ current = first
+ while (absindex >= current.end && current.next != null)
+ current = current.next
+ while (absindex >= current.end && !current.isLast) {
+ current = addMore()
+ }
+ current
+ }
+
+ /** The length of the character sequence
+ * Note: calling this method will force sequence to be read until the end.
+ */
+ def length: Int = {
+ while (!latest.isLast) addMore()
+ (latest.end min end) - start
+ }
+
+ /** The character at position `index'.
+ */
+ def charAt(index: Int) =
+ if (isDefinedAt(index)) page(index + start)(index + start)
+ else throw new IndexOutOfBoundsException(index.toString)
+
+ /** Is character sequence defined at `index'?
+ * 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 p = page(index + start); index + start < p.end
+ }
+
+ /** Optionally the character at position `index'. None is not in range.
+ */
+ override def get(index: Int) =
+ if (isDefinedAt(index)) Some(page(index + start)(index + start))
+ else None
+
+ /** the subsequence from index `start' up to and excluding
+ * the minimum of index `end' and the length of current sequence.
+ */
+ def subSequence(_start: Int, _end: Int) = {
+ page(start)
+ val s = start + _start
+ val e = if (_end == UndeterminedEnd) _end else start + _end
+ var f = first
+ while (f.end <= s && !f.isLast) f = f.next
+ new LazyCharSequence(more, f, s, e)
+ }
+
+ /** The subsequence from index `start' until the end of the current sequence
+ * This operation does not force reading to the end.
+ */
+ override def subSequence(start: Int): CharSequence =
+ subSequence(start, UndeterminedEnd)
+
+ /** Convert sequence to string */
+ override def toString = {
+ val buf = new StringBuilder
+ for (ch <- elements) buf append ch
+ buf.toString
+ }
+}
+
+
+/** Page containing up to PageSize characters of the input sequence.
+ */
+private class Page(val num: Int) {
+
+ private final val PageSize = 4096
+
+ /** The next page in the sequence */
+ var next : Page = null
+
+ /** A later page in the sequence, serves a cachae for pointing to last page */
+ var later : Page = this
+
+ /** The number of characters read into this page */
+ var filled: Int = 0
+
+ /** Is this page the permamnently last one in the sequence? Only true once `more'
+ * method has returned -1 to signal end of input. */
+ var isLast: Boolean = false
+
+ /** The character array */
+ final val chars = new Array[Char](PageSize)
+
+ /** The index of the first character in this page relative to the whole sequence */
+ final def start = num * PageSize
+
+ /** The index of the character following the last charcater in this page relative
+ * to the whole sequence */
+ final def end = start + filled
+
+ /** The currently last page in the sequence; might change as more charcaters are appended */
+ final def latest: Page = {
+ if (later.next != null) later = later.latest
+ later
+ }
+
+ /** The character at 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)
+ chars(index - start)
+ }
+
+ /** produces more characters by calling `more' and appends them on the current page,
+ * or fills a subsequent page if current page is full
+ * pre: if current page is full, it is the last one in the sequence.
+ */
+ final def addMore(more: (Array[Char], Int, Int) => Int): Page =
+ if (filled == PageSize) {
+ next = new Page(num + 1)
+ next.addMore(more)
+ } else {
+ val count = more(chars, filled, PageSize - filled)
+ if (count < 0) isLast = true
+ else filled += count
+ this
+ }
+}
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index 94f69f11d8..5525608cf5 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -73,7 +73,7 @@ object Predef {
// errors and asserts -------------------------------------------------
- def error(message: String): Nothing = throw new Error(message)
+ def error(message: String): Nothing = throw new RuntimeException(message)
def exit: Nothing = exit(0)
@@ -324,6 +324,7 @@ object Predef {
implicit def forceArrayProjection[A](x: Array.Projection[A]): Array[A] = x.force
/** any random access character seq (including rich string can be converted into a string */
implicit def forceRandomAccessCharSeq(x: runtime.RichString): String = x.mkString
+ implicit def lazyStreamToConsable[A](xs: => Stream[A]) = new runtime.StreamCons(xs)
def currentThread = java.lang.Thread.currentThread()
diff --git a/src/library/scala/Stream.scala b/src/library/scala/Stream.scala
index 957e14e361..1f9b233e4a 100644
--- a/src/library/scala/Stream.scala
+++ b/src/library/scala/Stream.scala
@@ -22,8 +22,18 @@ import Predef._
*/
object Stream {
+ def apply[A](xs: A*) = (xs :\ (empty: Stream[A]))(cons(_, _))
+
+ def unapplySeq[A](xs: Stream[A]): Option[Seq[A]] = Some(xs)
+
+ object lazy_:: {
+ def unapply[A](xs: Stream[A]): Option[(A, Stream[A])] =
+ if (xs.isEmpty) None
+ else Some(xs.head, xs.tail)
+ }
+
/** a stream with a definite size */
- trait Definite[+A] extends Stream[A] with Function0[Stream[A]] {
+ trait Definite[+A] extends Stream[A] with Function0[Stream[A]] {
override def hasDefiniteSize = true
override def apply = this
override def toString = super[Stream].toString
@@ -38,6 +48,7 @@ object Stream {
}
object cons {
+
/** A stream consisting of a given first element and remaining elements
* @param hd The first element of the result stream
* @param tl The remaining elements of the result stream
diff --git a/src/library/scala/collection/jcl/Map.scala b/src/library/scala/collection/jcl/Map.scala
index 2feed2ca82..8e921dcfc2 100644
--- a/src/library/scala/collection/jcl/Map.scala
+++ b/src/library/scala/collection/jcl/Map.scala
@@ -94,7 +94,7 @@ trait Map[K,E] extends MutableIterable[Tuple2[K,E]] with scala.collection.mutabl
new MutableIterator[(K,E)] {
def next = i.next
def hasNext = i.hasNext
- def remove : Unit = throw new Error
+ def remove : Unit = throw new NoSuchMethodException
}
}
override def removeKey(key : K) = {
diff --git a/src/library/scala/collection/jcl/MutableIterable.scala b/src/library/scala/collection/jcl/MutableIterable.scala
index 0fed9954e5..3988ed8d93 100644
--- a/src/library/scala/collection/jcl/MutableIterable.scala
+++ b/src/library/scala/collection/jcl/MutableIterable.scala
@@ -91,7 +91,7 @@ trait MutableIterable[A] extends scala.Collection[A] {
new MutableIterator[A] {
def next = i.next
def hasNext = i.hasNext
- def remove : Unit = throw new Error
+ def remove : Unit = throw new NoSuchMethodException
}
}
def size = size0;
diff --git a/src/library/scala/runtime/RichString.scala b/src/library/scala/runtime/RichString.scala
index bf14a652a5..9c7facd1a7 100644
--- a/src/library/scala/runtime/RichString.scala
+++ b/src/library/scala/runtime/RichString.scala
@@ -14,7 +14,7 @@ package scala.runtime
import Predef._
import scala.util.matching.Regex
-final class RichString(val self: String) extends Proxy with RandomAccessSeq[Char] with Ordered[String] {
+final class RichString(val self: String) extends Proxy with CharSequence with RandomAccessSeq[Char] with Ordered[String] {
import RichString._
override def apply(n: Int) = self charAt n
override def length = self.length
@@ -74,6 +74,11 @@ final class RichString(val self: String) extends Proxy with RandomAccessSeq[Char
new RichString(buf.toString)
}
+ def charAt(index: Int) = self.charAt(index)
+
+ def subSequence(start: Int, end: Int): CharSequence =
+ new RichString(self.substring(start, end))
+
/** return n times the current string
*/
def * (n: Int): String = {
diff --git a/src/library/scala/runtime/StreamCons.scala b/src/library/scala/runtime/StreamCons.scala
new file mode 100755
index 0000000000..2bcb0bf45b
--- /dev/null
+++ b/src/library/scala/runtime/StreamCons.scala
@@ -0,0 +1,17 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2008, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id: RichString.scala 14350 2008-03-10 19:34:38Z odersky $
+
+
+package scala.runtime
+
+final class StreamCons[T](xs: => Stream[T]) {
+ def lazy_:: (x: T): Stream[T] = Stream.cons(x, xs)
+ def lazy_::: (ys: Stream[T]): Stream[T] = ys append xs
+}
diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala
index ae9fe6361b..947175f945 100644
--- a/src/library/scala/util/matching/Regex.scala
+++ b/src/library/scala/util/matching/Regex.scala
@@ -18,109 +18,72 @@ import java.util.regex.{Pattern, Matcher}
*
* @author Thibaud Hottelier
* @author Philipp Haller
+ * @author Martin Odersky
* @version 1.1, 29/01/2008
*
* @param regex A string representing a regular expression
* @param groupNames A mapping from names to indices in capture groups
*/
-class Regex(val regex: String, private var groupNames: Map[String, Int]) {
- private def buildMap(res: Map[String, Int], groupNames: Seq[String], i: Int): Map[String, Int] =
- if (i > groupNames.size)
- res
- else {
- val p = (groupNames(i - 1), i)
- buildMap(res + p, groupNames, i + 1)
- }
+class Regex(regex: String, groupNames: String*) {
- /** Create a <code>Regex</code> from a string.
- *
- * @param s The regular expression
- * @return A new <code>Regex</code> instance
- */
- def this(s: String) = this(s, null: Map[String, Int])
+ import Regex._
- /** Create a <code>Regex</code> from a string and
- * a sequence of group names.
- *
- * @param s The regular expression
- * @param groups The list of group names in the same order
- * as the capture groups in the regular expression
- * @return A new <code>Regex</code> instance
- */
- def this(s: String, groups: String*) = {
- this(s)
- groupNames = buildMap(Map[String, Int](), groups, 1)
- }
-
- /* Stores the compiled pattern at instantiation time */
+ /** The compiled pattern */
val pattern = Pattern.compile(regex)
- /* Builds a MatchData[String] from a Matcher */
- private def buildSeq(l: List[String], m: Matcher, i: Int): MatchData[String] =
- if (i == -1)
- new MatchData(l, groupNames)
- else
- buildSeq(m.group(i) :: l, m, i - 1)
-
- /* Builds a List[MatchData[String]] from a Matcher */
- private def doMatchAll(res: List[MatchData[String]], m: Matcher): List[MatchData[String]] =
- if (m.find())
- doMatchAll(res ::: List(buildSeq(Nil, m, m.groupCount())), m)
- else
- res
-
- /* Builds a List[String] from a Matcher */
- private def unapplySeq0(target: String): Option[List[String]] = {
- val m = pattern.matcher(target)
- if (m.matches())
- Some(buildSeq(Nil, m, m.groupCount()).getGroups.tail)
- else
- None
- }
-
/** Tries to match target (whole match) and returns
* the matches.
*
* @param target The string to match
* @return The matches
*/
- def unapplySeq(target: Any): Option[List[String]] =
- if (target.isInstanceOf[String])
- unapplySeq0(target.asInstanceOf[String])
- else if (target.isInstanceOf[MatchData[_]])
- unapplySeq0(target.asInstanceOf[MatchData[String]]())
- else
+ def unapplySeq(target: Any): Option[List[String]] = target match {
+ case s: java.lang.CharSequence =>
+ val m = pattern.matcher(s)
+ if (m.matches) Some((1 to m.groupCount).toList map m.group)
+ else None
+ case Match(s) =>
+ unapplySeq(s)
+ case _ =>
None
+ }
- /** Creates a <code>MatchData[String]</code> from a string.
- * This is used in for-comprehensions to iterate over matches.
- *
- * @param s The string to match
- * @return The MatchData[String] instance
+ /** Return all matches of this regexp in given character sequence as an iterator
*/
- def ~~(s: String) = matchAll(s)
+ def findAllIn(source: CharSequence) = new Regex.MatchIterator(source, this, groupNames)
- /** Returns all matches of target string.
- *
- * @param target The string to match
- * @return All matches in a list of <code>MatchData[String]</code>
+ /** Return optionally first matching string of this regexp in given character sequence,
+ * None if it does not exist.
*/
- def matchAll(target: String): List[MatchData[String]] = {
- val m = pattern.matcher(target)
- doMatchAll(Nil, m)
+ def findFirstIn(source: CharSequence): Option[String] = {
+ val m = pattern.matcher(source)
+ if (m.find) Some(m.group) else None
}
- /** Returns the first match of target string.
- *
- * @param target The string to match
- * @return The first match as <code>MatchData[String]</code>
+ /** Return optionally first match of this regexp in given character sequence,
+ * None if it does not exist.
*/
- def matchFirst(target: String): Option[MatchData[String]] = {
- val m = pattern.matcher(target)
- if (!m.find())
- None
- else
- Some(buildSeq(Nil, m, m.groupCount()))
+ def findFirstMatchIn(source: CharSequence): Option[Match] = {
+ val m = pattern.matcher(source)
+ if (m.find) Some(new Match(source, m, groupNames)) else None
+ }
+
+ /** Return optionally match of this regexp at the beginning of the
+ * given character sequence, or None if regexp matches no prefix
+ * of the character sequence.
+ */
+ def findPrefixOf(source: CharSequence): Option[String] = {
+ val m = pattern.matcher(source)
+ if (m.lookingAt) Some(m.group) else None
+ }
+
+ /** Return optionally match of this regexp at the beginning of the
+ * given character sequence, or None if regexp matches no prefix
+ * of the character sequence.
+ */
+ def findPrefixMatchOf(source: CharSequence): Option[Match] = {
+ val m = pattern.matcher(source)
+ if (m.lookingAt) Some(new Match(source, m, groupNames)) else None
}
/** Replaces all matches by a string.
@@ -129,7 +92,7 @@ class Regex(val regex: String, private var groupNames: Map[String, Int]) {
* @param replacement The string that will replace each match
* @return The resulting string
*/
- def replaceAll(target: String, replacement: String): String = {
+ def replaceAllIn(target: CharSequence, replacement: String): String = {
val m = pattern.matcher(target)
m.replaceAll(replacement)
}
@@ -140,43 +103,170 @@ class Regex(val regex: String, private var groupNames: Map[String, Int]) {
* @param replacement The string that will replace the match
* @return The resulting string
*/
- def replaceFirst(target: String, replacement: String): String = {
+ def replaceFirstIn(target: CharSequence, replacement: String): String = {
val m = pattern.matcher(target)
m.replaceFirst(replacement)
}
- /** Returns true if the whole string matches.
- *
- * @param target The string to match
- * @return <code>true</code> iff the whole string matches
+ /** The string defining the regular expression */
+ override def toString = regex
+}
+
+/** This object defines inner classes that describe
+ * regex matches. The class hirrachy is as follows.
+ *
+ * MatchData
+ * | \
+ * MatchIterator Match
+ */
+object Regex {
+
+ /** This class provides methods to access
+ * the details of a match.
*/
- def matchesAll(target: String): Boolean = {
- val m = pattern.matcher(target)
- m.find()
+ trait MatchData {
+
+ /** The source from where the match originated */
+ val source: CharSequence
+
+ /** The names of the groups, or some empty sequence if one defined */
+ val groupNames: Seq[String]
+
+ /** The index of the first matched character */
+ def start: Int
+
+ /** The index of the first matched character in group <code>i</code> */
+ def start(i: Int): Int
+
+ /** The index of the last matched character */
+ def end: Int
+
+ /** The number of subgroups */
+ def groupCount: Int
+
+ /** The index following the last matched character in group <code>i</code> */
+ def end(i: Int): Int
+
+ /** The matched string */
+ def matched: String = source.subSequence(start, end).toString
+
+ /** The matched string in group <code>i</code> */
+ def group(i: Int): String = source.subSequence(start(i), end(i)).toString
+
+ /** All matched subgroups, i.e. not including group(0) */
+ def subgroups: List[String] = (1 to groupCount).toList map group
+
+ /** The char sequence before first character of match */
+ def before: CharSequence = source.subSequence(0, start)
+
+ /** The char sequence before first character of match in group <code>i</code> */
+ def before(i: Int): CharSequence = source.subSequence(0, start(i))
+
+ /** Returns char sequence after last character of match */
+ def after: CharSequence = source.subSequence(end)
+
+ /** The char sequence after last character of match in group <code>i</code> */
+ def after(i: Int): CharSequence = source.subSequence(end(i))
+
+ private lazy val nameToIndex: Map[String, Int] = Map() ++ ("" :: groupNames.toList).zipWithIndex
+
+ /** Returns the group with given name
+ *
+ * @param id The group name
+ * @return The requested group
+ * @throws <code>NoSuchElementException</code> if the requested
+ * group name is not defined
+ */
+ def group(id: String): String = nameToIndex.get(id) match {
+ case None => throw new NoSuchElementException("group name "+id+" not defined")
+ case Some(index) => group(index)
+ }
+
+ /** The matched string; equivalent to <code>matched.toString</code> */
+ override def toString = matched
+
}
- /** Returns <code>true</code> iff the string or one of its substrings match.
- *
- * @param target The string to match
- * @return <code>true</code> iff the string matches
+ /** A case class for a succesful match.
*/
- def matches(target: String): Boolean = {
- val m = pattern.matcher(target)
- m.matches()
+ class Match(val source: CharSequence,
+ matcher: Matcher,
+ val groupNames: Seq[String]) extends MatchData {
+
+ /** The index of the first matched character */
+ val start = matcher.start
+
+ /** The index following the last matched character */
+ val end = matcher.end
+
+ /** The number of subgroups */
+ def groupCount = matcher.groupCount
+
+ private lazy val starts: Array[Int] =
+ ((1 to groupCount) map matcher.start).toArray
+ private lazy val ends: Array[Int] =
+ ((1 to groupCount) map matcher.end).toArray
+
+ /** The index of the first matched character in group <code>i</code> */
+ def start(i: Int) = starts(i)
+
+ /** The index following the last matched character in group <code>i</code> */
+ def end(i: Int) = ends(i)
+
+ /** The match itself with matcher-dependent lazy vals forced,
+ * so that match is valid even once matcher is advanced
+ */
+ def force: this.type = { starts; ends; this }
}
- override def toString = """regex"""+".r"
-}
+ /** An extractor object for Matches, yielding the matched string */
+ object Match {
+ def unapply(m: Match): Some[String] = Some(m.matched)
+ }
-/** Provides implicit conversions for regular expressions.
- */
-object Regex {
- /** Promotes a string to <code>MatchableString</code> so that <code>=~</code> can be used */
- implicit def stringToMatchableString(s: String) = new MatchableString(s)
+ /** A class to step through a sequence of regex matches
+ */
+ class MatchIterator(val source: CharSequence, val regex: Regex, val groupNames: Seq[String])
+ extends Iterator[String] with MatchData { self =>
+
+ private val matcher = regex.pattern.matcher(source)
+ private var nextSeen = false
+
+ /** Is there another match? */
+ def hasNext: Boolean = {
+ if (!nextSeen) nextSeen = matcher.find()
+ nextSeen
+ }
+
+ /** The next matched substring of `source' */
+ def next: String = {
+ if (!hasNext) throw new NoSuchElementException
+ nextSeen = false
+ matcher.group
+ }
+
+ /** The index of the first matched character */
+ def start: Int = matcher.start
+
+ /** The index of the first matched character in group <code>i</code> */
+ def start(i: Int): Int = matcher.start(i)
+
+ /** The index of the last matched character */
+ def end: Int = matcher.end
+
+ /** The index following the last matched character in group <code>i</code> */
+ def end(i: Int): Int = matcher.end(i)
- /** Allows treating an <code>Option</code> as a Boolean. */
- implicit def optionToBoolean(o: Option[MatchData[String]]) = o.isDefined
+ /** The number of subgroups */
+ def groupCount = matcher.groupCount
- /** Promotes a string to a <code>Regex</code>. */
- implicit def stringToRegex(s: String) = new Regex(s)
+ /** Convert to an iterator that yields MatchData elements instead of Strings */
+ def matchData = new Iterator[Match] {
+ def hasNext = self.hasNext
+ def next = { self.next; new Match(source, matcher, groupNames).force }
+ }
+ }
}
+
+
+
diff --git a/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala b/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala
new file mode 100644
index 0000000000..6aceb5b3bc
--- /dev/null
+++ b/src/library/scala/util/parsing/combinator/JavaTokenParsers.scala
@@ -0,0 +1,24 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id: Parsers.scala 12357 2007-07-18 21:55:08Z moors $
+
+package scala.util.parsing.combinator
+
+trait JavaTokenParsers extends RegexParsers {
+ def ident: Parser[String] =
+ """[a-zA-Z_]\w*""".r
+ def wholeNumber: Parser[String] =
+ """-?\d+""".r
+ def decimalNumber: Parser[String] =
+ """(\d+(\.\d*)?|\d*.\d+)""".r
+ def stringLiteral: Parser[String] =
+ ("\""+"""([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})*"""+"\"").r
+ def floatingPointNumber: Parser[String] =
+ """-?(\d+(\.\d*)?|\d*\.\d+)[eEfFdD]?([+-]?\d+)?""".r
+}
diff --git a/src/library/scala/util/parsing/combinator/RegexParsers.scala b/src/library/scala/util/parsing/combinator/RegexParsers.scala
index 4b76a8ee79..18e7f4d8e4 100755
--- a/src/library/scala/util/parsing/combinator/RegexParsers.scala
+++ b/src/library/scala/util/parsing/combinator/RegexParsers.scala
@@ -12,7 +12,7 @@ package scala.util.parsing.combinator
import java.util.regex.Pattern
import scala.util.matching.Regex
-import scala.util.parsing.input.CharSequenceReader
+import scala.util.parsing.input._
trait RegexParsers extends Parsers {
@@ -20,16 +20,16 @@ trait RegexParsers extends Parsers {
var skipWhitespace = true
- private val whiteSpacePat = Pattern compile """\s+"""
+ private val whiteSpace = """\s+""".r
- private def handleWhiteSpace(source: CharSequence, offset: Int): Int = {
- var start = offset
- if (skipWhitespace) {
- val wsm = whiteSpacePat.matcher(source.subSequence(offset, source.length))
- if (wsm.lookingAt) start += wsm.end
- }
- start
- }
+ private def handleWhiteSpace(source: CharSequence, offset: Int): Int =
+ if (skipWhitespace)
+ (whiteSpace findPrefixMatchOf (source subSequence offset)) match {
+ case Some(matched) => offset + matched.end
+ case None => offset
+ }
+ else
+ offset
/** A parser that matches a literal string */
implicit def literal(s: String): Parser[String] = new Parser[String] {
@@ -39,14 +39,14 @@ trait RegexParsers extends Parsers {
val start = handleWhiteSpace(source, offset)
var i = 0
var j = start
- while (i < s.length && j < source.length && s.charAt(i) == source.charAt(j)) {
+ while (i < s.length && source.isDefinedAt(j) && s.charAt(i) == source.charAt(j)) {
i += 1
j += 1
}
if (i == s.length)
Success(source.subSequence(start, j).toString, in.drop(j - offset))
else
- Failure("`"+s+"' expected", in.drop(start - offset))
+ Failure("`"+s+"' expected but `"+in.first+"' found", in.drop(start - offset))
}
}
@@ -56,20 +56,29 @@ trait RegexParsers extends Parsers {
val source = in.source
val offset = in.offset
val start = handleWhiteSpace(source, offset)
- val pm = r.pattern.matcher(source.subSequence(start, source.length))
- if (pm.lookingAt)
- Success(source.subSequence(start, start + pm.end).toString,
- in.drop(start + pm.end - offset))
- else
- Failure("string matching regex `"+r.regex+"' expected", in.drop(start - offset))
+ (r findPrefixMatchOf (source subSequence start)) match {
+ case Some(matched) =>
+ Success(source.subSequence(start, start + matched.end).toString,
+ in.drop(start + matched.end - offset))
+ case None =>
+ Failure("string matching regex `+r+' expected but `"+in.first+"' found", in.drop(start - offset))
+ }
}
}
/** Parse some prefix of character sequence `in' with parser `p' */
- def parse[T](p: Parser[T])(in: CharSequence): ParseResult[T] =
+ def parse[T](p: Parser[T], in: CharSequence): ParseResult[T] =
p(new CharSequenceReader(in))
+ /** Parse some prefix of reader `in' with parser `p' */
+ def parse[T](p: Parser[T], in: Reader[Char]): ParseResult[T] =
+ p(in)
+
/** Parse all of character sequence `in' with parser `p' */
- def parseAll[T](p: Parser[T])(in: CharSequence): ParseResult[T] =
- parse(phrase(p))(in)
+ def parseAll[T](p: Parser[T], in: CharSequence): ParseResult[T] =
+ parse(phrase(p), in)
+
+ /** Parse all of reader `in' with parser `p' */
+ def parseAll[T](p: Parser[T], in: Reader[Char]): ParseResult[T] =
+ parse(phrase(p), in)
}
diff --git a/src/library/scala/util/parsing/combinator/lexical/Scanners.scala b/src/library/scala/util/parsing/combinator/lexical/Scanners.scala
index d4f3103a71..f1a930ecdf 100644
--- a/src/library/scala/util/parsing/combinator/lexical/Scanners.scala
+++ b/src/library/scala/util/parsing/combinator/lexical/Scanners.scala
@@ -66,8 +66,8 @@ trait Scanners extends Parsers {
}
private def skip(in: Reader[Char]) = if (in.atEnd) in else in.rest
- def source: CharSequence = in.source
- def offset: Int = in.offset
+ override def source: CharSequence = in.source
+ override def offset: Int = in.offset
def first = tok
def rest = new Scanner(rest2)
def pos = rest1.pos
diff --git a/src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala b/src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala
index d4479d8045..15e9542bb5 100644
--- a/src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala
+++ b/src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala
@@ -66,8 +66,8 @@ trait Scanners extends Parsers {
}
private def skip(in: Reader[Char]) = if (in.atEnd) in else in.rest
- def source: CharSequence = in.source
- def offset: Int = in.offset
+ override def source: CharSequence = in.source
+ override def offset: Int = in.offset
def first = tok
def rest = new Scanner(rest2)
def pos = rest1.pos
diff --git a/src/library/scala/util/parsing/input/CharArrayPosition.scala b/src/library/scala/util/parsing/input/CharArrayPosition.scala
index 8d63b12332..bf86e2e104 100644
--- a/src/library/scala/util/parsing/input/CharArrayPosition.scala
+++ b/src/library/scala/util/parsing/input/CharArrayPosition.scala
@@ -26,10 +26,10 @@ class CharArrayPosition(val source: Array[Char], val line: Int, val column: Int)
// TODO: this could be implemented more high-level:
// return the string representation of the sub-array of source that starts
// after the (lnum-1)'ed '\n' up to (but not including) the (lnum)'ed '\n'
- protected def lineContents(lnum: Int) = {
+ protected def lineContents = {
var i = 0
var l = 1
- while (i < source.length && l < lnum) {
+ while (i < source.length && l < line) {
while (i < source.length && source(i) != '\n') i += 1
i += 1
l += 1
diff --git a/src/library/scala/util/parsing/input/CharArrayReader.scala b/src/library/scala/util/parsing/input/CharArrayReader.scala
index b7c576c631..44e1b6eb6e 100644
--- a/src/library/scala/util/parsing/input/CharArrayReader.scala
+++ b/src/library/scala/util/parsing/input/CharArrayReader.scala
@@ -16,7 +16,9 @@ package scala.util.parsing.input
*/
object CharArrayReader {
final val EofCh = '\032'
- final val CR = '\015'
+
+ /** @deprecated This should probably be LF instead? */
+ @deprecated final val CR = '\015'
}
/** A character array reader reads a stream of characters (keeping track of their positions)
@@ -30,7 +32,7 @@ object CharArrayReader {
* @author Martin Odersky, Adriaan Moors
*/
class CharArrayReader(chars: Array[Char], index: Int)
-extends CharSequenceReader(new CharArraySequence(chars), index) {
+extends CharSequenceReader(CharSequence.fromArray(chars), index) {
def this(chars: Array[Char]) = this(chars, 0)
diff --git a/src/library/scala/util/parsing/input/CharArraySequence.scala b/src/library/scala/util/parsing/input/CharArraySequence.scala
deleted file mode 100755
index 9acca84df2..0000000000
--- a/src/library/scala/util/parsing/input/CharArraySequence.scala
+++ /dev/null
@@ -1,37 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-// $Id:
-
-
-package scala.util.parsing.input
-
-/** An implementation of java.lang.CharSequence over a character array
- *
- * @author Martin Odersky
- */
-class CharArraySequence(source: Array[Char], start: Int, end: Int) extends CharSequence {
-
- def this(source: Array[Char], start: Int) = this(source, start, source.length)
-
- def this(source: Array[Char]) = this(source, 0)
-
- if (start < 0) throw new IndexOutOfBoundsException
- if (end > source.length) throw new IndexOutOfBoundsException
-
- def charAt(index: Int) =
- if (start + index < end) source(index + start)
- else throw new IndexOutOfBoundsException
-
- def length: Int = if (end < start) 0 else end - start
-
- def subSequence(_start: Int, _end: Int) =
- new CharArraySequence(source, start + _start, start + _end)
-
- override def toString = new String(source, start, end - start)
-}
diff --git a/src/library/scala/util/parsing/input/CharSequenceReader.scala b/src/library/scala/util/parsing/input/CharSequenceReader.scala
index 453a808f08..adcd6b99f0 100755
--- a/src/library/scala/util/parsing/input/CharSequenceReader.scala
+++ b/src/library/scala/util/parsing/input/CharSequenceReader.scala
@@ -16,18 +16,18 @@ package scala.util.parsing.input
*/
object CharSequenceReader {
final val EofCh = '\032'
- final val CR = '\015'
}
/** A character array reader reads a stream of characters (keeping track of their positions)
* from an array.
*
* @param source the source sequence
- * @param index starting index.
+ * @param offset starting offset.
*
* @author Martin Odersky
*/
-class CharSequenceReader(val source: CharSequence, index: Int) extends Reader[Char] {
+class CharSequenceReader(override val source: CharSequence,
+ override val offset: Int) extends Reader[Char] {
import CharSequenceReader._
/** Construct a <code>CharSequenceReader</code> with its first element at
@@ -35,22 +35,10 @@ class CharSequenceReader(val source: CharSequence, index: Int) extends Reader[Ch
*/
def this(source: CharSequence) = this(source, 0)
- /** The effective offset into source
- * This is the same as index, except that CR characters at the end of a line
- * are always skipped.
- */
- lazy val offset: Int =
- if (index + 1 < source.length &&
- source.charAt(index) == CR && source.charAt(index + 1) == '\n')
- index + 1
- else
- index
-
/** Returns the first element of the reader, or EofCh if reader is at its end
*/
def first =
- if (offset == source.length) EofCh
- else source.charAt(offset)
+ if (source.isDefinedAt(offset)) source(offset) else EofCh
/** Returns a CharSequenceReader consisting of all elements except the first
*
@@ -59,8 +47,8 @@ class CharSequenceReader(val source: CharSequence, index: Int) extends Reader[Ch
* the rest of input.
*/
def rest: CharSequenceReader =
- if (offset == source.length) this
- else new CharSequenceReader(source, offset + 1)
+ if (source.isDefinedAt(offset)) new CharSequenceReader(source, offset + 1)
+ else this
/** The position of the first element in the reader
*/
@@ -69,11 +57,11 @@ class CharSequenceReader(val source: CharSequence, index: Int) extends Reader[Ch
/** true iff there are no more elements in this reader (except for trailing
* EofCh's)
*/
- def atEnd = offset == source.length
+ def atEnd = !source.isDefinedAt(offset)
/** Returns an abstract reader consisting of all elements except the first
* <code>n</code> elements.
*/
override def drop(n: Int): CharSequenceReader =
- new CharSequenceReader(source, (offset + n) min source.length)
+ new CharSequenceReader(source, offset + n)
}
diff --git a/src/library/scala/util/parsing/input/NoPosition.scala b/src/library/scala/util/parsing/input/NoPosition.scala
index 7c11a7c510..1337164394 100644
--- a/src/library/scala/util/parsing/input/NoPosition.scala
+++ b/src/library/scala/util/parsing/input/NoPosition.scala
@@ -20,5 +20,5 @@ object NoPosition extends Position {
def column = 0
override def toString = "<undefined position>"
override def longString = toString
- def lineContents(lnum: Int) = ""
+ def lineContents = ""
}
diff --git a/src/library/scala/util/parsing/input/OffsetPosition.scala b/src/library/scala/util/parsing/input/OffsetPosition.scala
index a29e195455..6bbc6fdcac 100755
--- a/src/library/scala/util/parsing/input/OffsetPosition.scala
+++ b/src/library/scala/util/parsing/input/OffsetPosition.scala
@@ -50,8 +50,8 @@ case class OffsetPosition(source: CharSequence, offset: Int) extends Position {
* @param lnum a 1-based integer index into the `document'
* @return the line at `lnum' (not including a newline)
*/
- def lineContents(lnum: Int): String =
- source.subSequence(index(lnum - 1), index(lnum)).toString
+ def lineContents: String =
+ source.subSequence(index(line - 1), index(line)).toString
/** Returns a string representation of the `Position', of the form `line.column' */
override def toString = line+"."+column
diff --git a/src/library/scala/util/parsing/input/Position.scala b/src/library/scala/util/parsing/input/Position.scala
index 64d2ecf3a1..6f375b3529 100644
--- a/src/library/scala/util/parsing/input/Position.scala
+++ b/src/library/scala/util/parsing/input/Position.scala
@@ -38,7 +38,7 @@ trait Position {
* @param lnum a 1-based integer index into the `document'
* @return the line at `lnum' (not including a newline)
*/
- protected def lineContents(lnum: Int): String
+ protected def lineContents: String
/** Returns a string representation of the `Position', of the form `line.column' */
override def toString = ""+line+"."+column
@@ -53,7 +53,7 @@ trait Position {
*<pre> List(this, is, a, line, from, the, document)
* ^</pre>
*/
- def longString = lineContents(line)+"\n"+(" " * (column - 1))+"^"
+ def longString = lineContents+"\n"+(" " * (column - 1))+"^"
/** Compare this position to another, by first comparing their line numbers,
* and then -- if necessary -- using the columns to break a tie.
diff --git a/src/library/scala/util/parsing/input/Reader.scala b/src/library/scala/util/parsing/input/Reader.scala
index f9d7115113..51cf7eeb47 100644
--- a/src/library/scala/util/parsing/input/Reader.scala
+++ b/src/library/scala/util/parsing/input/Reader.scala
@@ -11,17 +11,22 @@
package scala.util.parsing.input
+
/** An interface for streams of values that have positions.
*
* @author Martin Odersky, Adriaan Moors
*/
abstract class Reader[+T] {
- /** The source character sequence for this reader */
- def source: CharSequence
+ private[parsing] def source: CharSequence = this match {
+ case csr: CharSequenceReader => csr.source
+ case _ => throw new IllegalArgumentException("This kind of parser operates only on a CharSequenceReader")
+ }
- /** The current index into source */
- def offset: Int
+ private[parsing] def offset: Int = this match {
+ case csr: CharSequenceReader => csr.offset
+ case _ => throw new IllegalArgumentException("This kind of parser operates only on a CharSequenceReader")
+ }
/** Returns the first element of the reader
*/
@@ -41,7 +46,9 @@ abstract class Reader[+T] {
def drop(n: Int): Reader[T] = {
var r: Reader[T] = this
var cnt = n
- while (cnt > 0) r = r.rest
+ while (cnt > 0) {
+ r = r.rest; cnt -= 1
+ }
r
}
diff --git a/src/library/scala/util/parsing/input/StreamReader.scala b/src/library/scala/util/parsing/input/StreamReader.scala
index bad859d4c0..f8835ace25 100755
--- a/src/library/scala/util/parsing/input/StreamReader.scala
+++ b/src/library/scala/util/parsing/input/StreamReader.scala
@@ -21,11 +21,9 @@ import java.io.BufferedReader
*/
object StreamReader {
final val EofCh = '\032'
- final val CR = '\015'
def apply(in: java.io.Reader): StreamReader = {
- val bin = new BufferedReader(in)
- new StreamReader(bin, bin.readLine, 1, 1)
+ new StreamReader(new LazyCharSequence(in), 0, 1)
}
}
@@ -46,34 +44,31 @@ object StreamReader {
*
* @author Miles Sabin
*/
-sealed class StreamReader private (bin: BufferedReader, sourceLine: String, ln: Int, col: Int)
-extends Reader[Char] {
+sealed class StreamReader(source: CharSequence, offset: Int, lnum: Int) extends CharSequenceReader(source, offset) {
import StreamReader._
- def source: CharSequence = sourceLine
- def offset: Int = col-1
+ override def rest: CharSequenceReader =
+ if (offset == source.length) this
+ else if (source(offset) == '\n') new StreamReader(source.subSequence(offset + 1), 0, lnum + 1)
+ else new StreamReader(source, offset + 1, lnum)
- def first =
- if (sourceLine == null)
- EofCh
- else if (col > sourceLine.length)
- CR
- else
- sourceLine(col-1)
+ private def nextEol = {
+ var i = offset
+ while (i < source.length && source(i) != '\n' && source(i) != EofCh) i += 1
+ i
+ }
- def rest: StreamReader =
- if (sourceLine == null)
- this
- else if (col > sourceLine.length)
- new StreamReader(bin, bin.readLine, ln+1, 1)
+ override def drop(n: Int): StreamReader = {
+ val eolPos = nextEol
+ if (eolPos < offset + n && eolPos < source.length)
+ new StreamReader(source.subSequence(eolPos + 1), 0, lnum + 1).drop(offset + n - (eolPos + 1))
else
- new StreamReader(bin, sourceLine, ln, col+1)
-
- def pos: Position = new Position {
- def line = ln
- def column = col
- def lineContents(lnum: Int) = sourceLine
- }
+ new StreamReader(source, offset + n, lnum)
+ }
- def atEnd = (sourceLine == null)
+ override def pos: Position = new Position {
+ def line = lnum
+ def column = offset + 1
+ def lineContents = source.subSequence(0, nextEol).toString
+ }
}
diff --git a/test/partestall b/test/partestall
new file mode 100755
index 0000000000..a1f585e090
--- /dev/null
+++ b/test/partestall
@@ -0,0 +1,8 @@
+scala -cp ~/scala/build/quick/lib/partest:$HOME/scala/build/quick/lib/actors scala.tools.partest.nest.NestRunner --run
+scala -cp ~/scala/build/quick/lib/partest:$HOME/scala/build/quick/lib/actors scala.tools.partest.nest.NestRunner --jvm
+scala -cp ~/scala/build/quick/lib/partest:$HOME/scala/build/quick/lib/actors scala.tools.partest.nest.NestRunner --jvm5
+scala -cp ~/scala/build/quick/lib/partest:$HOME/scala/build/quick/lib/actors scala.tools.partest.nest.NestRunner --pos
+scala -cp ~/scala/build/quick/lib/partest:$HOME/scala/build/quick/lib/actors scala.tools.partest.nest.NestRunner --neg
+scala -cp ~/scala/build/quick/lib/partest:$HOME/scala/build/quick/lib/actors scala.tools.partest.nest.NestRunner --shootout
+sh scalatest --res
+sh scalatest --script
diff --git a/test/partestall.bat b/test/partestall.bat
new file mode 100755
index 0000000000..b8b8155225
--- /dev/null
+++ b/test/partestall.bat
@@ -0,0 +1,7 @@
+scala -cp C:\scala\build\quick\lib\partest;C:\scala\build\quick\lib\actors scala.tools.partest.nest.NestRunner --run
+scala -cp C:\scala\build\quick\lib\partest;C:\scala\build\quick\lib\actors scala.tools.partest.nest.NestRunner --jvm
+scala -cp C:\scala\build\quick\lib\partest;C:\scala\build\quick\lib\actors scala.tools.partest.nest.NestRunner --jvm5
+scala -cp C:\scala\build\quick\lib\partest;C:\scala\build\quick\lib\actors scala.tools.partest.nest.NestRunner --pos
+scala -cp C:\scala\build\quick\lib\partest;C:\scala\build\quick\lib\actors scala.tools.partest.nest.NestRunner --neg
+scala -cp C:\scala\build\quick\lib\partest;C:\scala\build\quick\lib\actors scala.tools.partest.nest.NestRunner --shootout
+