summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2008-04-07 15:57:07 +0000
committerMartin Odersky <odersky@gmail.com>2008-04-07 15:57:07 +0000
commit34fe33a61291ec51cb0598b3702b2c6de8ebb3f2 (patch)
treee5fe4f022df23cf216cc472d37c22e196328981b
parent67af71b370af294fef48d78efb3337274dbcecd3 (diff)
downloadscala-34fe33a61291ec51cb0598b3702b2c6de8ebb3f2.tar.gz
scala-34fe33a61291ec51cb0598b3702b2c6de8ebb3f2.tar.bz2
scala-34fe33a61291ec51cb0598b3702b2c6de8ebb3f2.zip
(1) Removed generation of $tag method for inter...
(1) Removed generation of $tag method for interfaces (2) improved type inference for clsoures (3) redesign of CharSequence and regex.
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Contexts.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala66
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Unapplies.scala2
-rw-r--r--src/library/scala/Predef.scala8
-rw-r--r--src/library/scala/Seq.scala12
-rw-r--r--src/library/scala/StringBuilder.scala7
-rwxr-xr-xsrc/library/scala/collection/immutable/PagedSeq.scala245
-rw-r--r--src/library/scala/runtime/RichString.scala9
-rw-r--r--src/library/scala/util/parsing/combinator/RegexParsers.scala29
-rw-r--r--src/library/scala/util/parsing/input/CharArrayReader.scala2
-rw-r--r--src/library/scala/util/parsing/input/CharSequenceReader.scala10
-rwxr-xr-xsrc/library/scala/util/parsing/input/PagedSeqReader.scala71
-rw-r--r--src/library/scala/util/parsing/input/Reader.scala15
-rw-r--r--src/library/scala/util/parsing/input/StreamReader.scala43
-rw-r--r--test/files/neg/bug414.check2
-rw-r--r--test/files/run/caseclasses.scala9
19 files changed, 492 insertions, 70 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
index fd1db30e74..e7c33cc426 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -2200,9 +2200,7 @@ trait Parsers extends NewScanners with MarkupParsers {
template, template.parents, makeSelfDef(nme.WILDCARD, thistpe), template.body)
} else syntaxError("`requires' cannot be combined with explicit self type", false)
}
- val mods1 = if (mods.hasFlag(Flags.TRAIT) &&
- (template.body forall treeInfo.isInterfaceMember))
- mods | Flags.INTERFACE
+ val mods1 = if (isInterface(mods, template.body)) mods | Flags.INTERFACE
else mods
val result = ClassDef(mods1, name, tparams, template)
implicitClassViews = savedViews
@@ -2271,6 +2269,9 @@ trait Parsers extends NewScanners with MarkupParsers {
}
}
+ def isInterface(mods: Modifiers, body: List[Tree]) =
+ (mods.hasFlag(Flags.TRAIT) && (body forall treeInfo.isInterfaceMember))
+
/** ClassTemplateOpt ::= extends ClassTemplate | [[extends] TemplateBody]
* TraitTemplateOpt ::= extends TraitTemplate | [[extends] TemplateBody]
*/
@@ -2286,7 +2287,10 @@ trait Parsers extends NewScanners with MarkupParsers {
(List(), List(List()), self, body)
}
var parents = parents0
- if (name != nme.ScalaObject.toTypeName) parents = parents ::: List(scalaScalaObjectConstr)
+ if (name != nme.ScalaObject.toTypeName && !isInterface(mods, body))
+ parents = parents ::: List(scalaScalaObjectConstr)
+ if (parents.isEmpty)
+ parents = List(scalaAnyRefConstr)
if (mods.hasFlag(Flags.CASE)) parents = parents ::: List(productConstr)
val tree = Template(parents, self, constrMods, vparamss, argss, body)
// @S: if nothing parsed, don't use next position!
diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
index 758a006e0e..d0e90a2fe2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala
@@ -110,7 +110,8 @@ trait Contexts { self: Analyzer =>
var checking = false
var retyping = false
- var savedTypeBounds: List[(Symbol, Type)] = List()
+ var savedTypeBounds: List[(Symbol, Type)] = List() // saved type bounds
+ // for type parameters which are narrowed in a GADT
def intern0 : Context = {
if (this eq NoContext) return this
diff --git a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
index 7b705036ac..1c6412419d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/EtaExpansion.scala
@@ -19,6 +19,19 @@ trait EtaExpansion { self: Analyzer =>
import global._
import posAssigner.atPos
+ object etaExpansion {
+ def unapply(tree: Tree): Option[(List[ValDef], Tree, List[Tree])] = tree match {
+ case Function(vparams, Apply(fn, args))
+ if (List.forall2(vparams, args) {
+ case (vparam, Ident(name)) => vparam.name == name
+ case _ => false
+ }) =>
+ Some((vparams, fn, args))
+ case _ =>
+ None
+ }
+ }
+
/** <p>
* Expand partial function applications of type <code>type</code>.
* </p><pre>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 1223328c96..c118df8a54 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -1150,7 +1150,7 @@ trait Infer {
val ptvars = ptparams map freshVar
val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
if (!isPopulated(tp, pt1)) {
- error(pos, "pattern type is incompatibe with expected type"+foundReqMsg(pattp, pt))
+ error(pos, "pattern type is incompatible with expected type"+foundReqMsg(pattp, pt))
return pattp
}
ptvars foreach instantiateTypeVar
@@ -1169,7 +1169,7 @@ trait Infer {
if (pat.tpe <:< pt1)
ptvars foreach instantiateTypeVar
else
- error(pat.pos, "pattern type is incompatibe with expected type"+foundReqMsg(pat.tpe, pt))
+ error(pat.pos, "pattern type is incompatible with expected type"+foundReqMsg(pat.tpe, pt))
}
object toOrigin extends TypeMap {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 12e0e63960..2cdbb3d57d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1449,10 +1449,22 @@ trait Typers { self: Analyzer =>
errorTree(fun, "wrong number of parameters; expected = " + argpts.length)
else {
val vparamSyms = List.map2(fun.vparams, argpts) { (vparam, argpt) =>
- if (vparam.tpt.isEmpty)
+ if (vparam.tpt.isEmpty) {
vparam.tpt.tpe =
if (isFullyDefined(argpt)) argpt
else {
+ fun match {
+ case etaExpansion(vparams, fn, args) if !codeExpected =>
+ println("typing eta "+fn)
+ silent(_.typed(fn, funMode(mode), pt)) match {
+ case fn1: Tree =>
+ val ftpe = normalize(fn1.tpe) baseType FunctionClass(fun.vparams.length)
+ if (isFunctionType(ftpe) && isFullyDefined(ftpe))
+ return typedFunction(fun, mode, ftpe)
+ case _ =>
+ }
+ case _ =>
+ }
error(
vparam.pos,
"missing parameter type"+
@@ -1460,6 +1472,7 @@ trait Typers { self: Analyzer =>
else ""))
ErrorType
}
+ }
enterSym(context, vparam)
if (context.retyping) context.scope enter vparam.symbol
vparam.symbol
@@ -1593,6 +1606,31 @@ trait Typers { self: Analyzer =>
}
}
+ /** Does function need to be instantiated, because a missing parameter
+ * in an argument closure overlaps with an uninstantiated formal?
+ */
+ def needsInstantiation(tparams: List[Symbol], formals: List[Type], args: List[Tree]) = {
+ def isLowerBounded(tparam: Symbol) = {
+ val losym = tparam.info.bounds.lo.typeSymbol
+ losym != AllClass && losym != AllRefClass
+ }
+ List.exists2(formals, args) {
+ case (formal, Function(vparams, _)) =>
+ (vparams exists (_.tpt.isEmpty)) &&
+ vparams.length <= MaxFunctionArity &&
+ (formal baseType FunctionClass(vparams.length) match {
+ case TypeRef(_, _, formalargs) =>
+ List.exists2(formalargs, vparams) ((formalarg, vparam) =>
+ vparam.tpt.isEmpty && (tparams exists (formalarg contains))) &&
+ (tparams forall isLowerBounded)
+ case _ =>
+ false
+ })
+ case _ =>
+ false
+ }
+ }
+
/**
* @param tree ...
* @param fun0 ...
@@ -1604,12 +1642,19 @@ trait Typers { self: Analyzer =>
def doTypedApply(tree: Tree, fun0: Tree, args: List[Tree], mode: Int, pt: Type): Tree = {
var fun = fun0
if (fun.hasSymbol && (fun.symbol hasFlag OVERLOADED)) {
- // preadapt symbol to number of arguments given
- val argtypes = args map (arg => AllClass.tpe)
+ // preadapt symbol to number and shape of arguments given
+ def shapeType(arg: Tree): Type = arg match {
+ case Function(vparams, body) =>
+ functionType(vparams map (vparam => AnyClass.tpe), shapeType(body))
+ case _ =>
+ AllClass.tpe
+ }
+ val argtypes = args map shapeType
val pre = fun.symbol.tpe.prefix
var sym = fun.symbol filter { alt =>
isApplicableSafe(context.undetparams, followApply(pre.memberType(alt)), argtypes, pt)
}
+ //println("narrowed to "+sym+":"+sym.info+"/"+argtypes)
if (sym hasFlag OVERLOADED) {
// eliminate functions that would result from tupling transforms
val sym1 = sym filter (alt => hasExactlyNumParams(followApply(alt.tpe), argtypes.length))
@@ -1673,6 +1718,10 @@ trait Typers { self: Analyzer =>
atPos(tree.pos) { gen.mkNil setType restpe }
} else
constfold(copy.Apply(tree, fun, args2).setType(ifPatternSkipFormals(restpe)))
+ } else if (needsInstantiation(tparams, formals, args1)) {
+ //println("needs inst "+fun+" "+tparams+"/"+(tparams map (_.info)))
+ inferExprInstance(fun, tparams, WildcardType)
+ doTypedApply(tree, fun, args1, mode, pt)
} else {
assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
val lenientTargs = protoTypeArgs(tparams, formals, mt.resultApprox, pt)
@@ -3527,9 +3576,14 @@ trait Typers { self: Analyzer =>
List()
}
- def implicitManifest(pt: Type): Tree = pt match {
- case TypeRef(_, ManifestClass, List(arg)) => manifestOfType(pos, arg)
- case _ => EmptyTree
+ def implicitManifest(pt: Type): Tree = {
+ // test below is designed so that ManifestClass need not be loaded
+ // (because it's not available everywhere)
+ if (pt.typeSymbol.fullNameString == "scala.reflect.Manifest")
+ pt match {
+ case TypeRef(_, ManifestClass, List(arg)) => manifestOfType(pos, arg)
+ }
+ else EmptyTree
}
var tree = searchImplicit(context.implicitss, true)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
index f2247f813c..e077329d4c 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala
@@ -135,7 +135,7 @@ trait Unapplies { self: Analyzer =>
*/
def caseModuleDef(cdef: ClassDef): ModuleDef = atPos(cdef.pos) {
var parents = List(gen.scalaScalaObjectConstr)
- if (cdef.tparams.isEmpty && constrParams(cdef).length == 1)
+ if (!(cdef.mods hasFlag ABSTRACT) && cdef.tparams.isEmpty && constrParams(cdef).length == 1)
parents = gen.scalaFunctionConstr(constrParams(cdef).head map (_.tpt),
Ident(cdef.name)) :: parents
ModuleDef(
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index c7a01d6642..387f5c92d3 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -344,6 +344,12 @@ object Predef {
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()
+ implicit def seqToCharSequence(xs: RandomAccessSeq[Char]): CharSequence = new CharSequence {
+ def length: Int = xs.length
+ def charAt(index: Int): Char = xs(index)
+ def subSequence(start: Int, end: Int): CharSequence = seqToCharSequence(xs.slice(start, end))
+ override def toString: String = xs.mkString("")
+ }
+ def currentThread = java.lang.Thread.currentThread()
}
diff --git a/src/library/scala/Seq.scala b/src/library/scala/Seq.scala
index bc075fb745..6b545ae6e7 100644
--- a/src/library/scala/Seq.scala
+++ b/src/library/scala/Seq.scala
@@ -313,8 +313,8 @@ trait Seq[+A] extends AnyRef with PartialFunction[Int, A] with Collection[A] {
result.toList
}
- /** A sub-sequence of <code>len</code> elements
- * starting at index <code>from</code> (non-strict)
+ /** A sub-sequence starting at index <code>from</code>
+ * and ending (non-inclusive) at index <code>until</code> (non-strict)
*
* @param from The index of the first element of the slice
* @param until The index of the element following the slice
@@ -323,6 +323,14 @@ trait Seq[+A] extends AnyRef with PartialFunction[Int, A] with Collection[A] {
*/
def slice(from: Int, until: Int): Seq[A] = drop(from).take(until - from)
+ /** A sub-sequence starting at index <code>from</code>
+ * and extending up to the length of the current sequence (non-strict)
+ *
+ * @param from The index of the first element of the slice
+ * @throws IndexOutOfBoundsException if <code>from &lt; 0</code>
+ */
+ def slice(from: Int): Seq[A] = slice(from, length)
+
/** Returns the longest prefix of this sequence whose elements satisfy
* the predicate <code>p</code>.
*
diff --git a/src/library/scala/StringBuilder.scala b/src/library/scala/StringBuilder.scala
index 92ee3b9ac8..f6da576b07 100644
--- a/src/library/scala/StringBuilder.scala
+++ b/src/library/scala/StringBuilder.scala
@@ -943,4 +943,11 @@ object StringBuilder {
}
-1
}
+
+ implicit def toCharSequence(sb: StringBuilder): java.lang.CharSequence = new java.lang.CharSequence {
+ def length: Int = sb.length
+ def charAt(index: Int): Char = sb.charAt(index)
+ def subSequence(start: Int, end: Int): java.lang.CharSequence = sb.substring(start, end)
+ override def toString: String = sb.toString
+ }
}
diff --git a/src/library/scala/collection/immutable/PagedSeq.scala b/src/library/scala/collection/immutable/PagedSeq.scala
new file mode 100755
index 0000000000..de034e67dd
--- /dev/null
+++ b/src/library/scala/collection/immutable/PagedSeq.scala
@@ -0,0 +1,245 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id: PagedSeq.scala 14497 2008-04-04 12:09:06Z washburn $
+
+
+package scala.collection.immutable
+
+import java.io._
+import util.matching.Regex
+
+
+/** The PagedSeq object defines a lazy implementations of
+ * a random access sequence.
+ */
+object PagedSeq {
+ final val UndeterminedEnd = Math.MAX_INT
+
+ /** Constructs a character sequence from a character iterator */
+ def fromIterator[T](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 character sequence from a character iterable */
+ def fromIterable[T](source: Iterable[T]): PagedSeq[T] =
+ fromIterator(source.elements)
+
+ /** Constructs a 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 character sequence from a string iterable */
+ def fromStrings(source: Iterable[String]): PagedSeq[Char] =
+ 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]): PagedSeq[Char] = {
+ 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]): PagedSeq[Char] =
+ fromLines(source.elements)
+
+ /** Constructs a character sequence from an input reader
+ */
+ def fromReader(source: Reader): PagedSeq[Char] =
+ new PagedSeq(source.read(_: Array[Char], _: Int, _: Int))
+
+ /** Constructs a character sequence from an input file
+ */
+ def fromFile(source: File): PagedSeq[Char] =
+ fromReader(new FileReader(source))
+
+ /** Constructs a character sequence from a file with given name
+ */
+ def fromFile(source: String): PagedSeq[Char] =
+ fromFile(new File(source))
+
+ /** Constructs a character sequence from a scala.io.Source value
+ */
+ def fromSource(source: 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.
+ *
+ * @author Martin Odersky
+ */
+class PagedSeq[T] protected (more: (Array[T], Int, Int) => Int,
+ first: Page[T], start: Int, end: Int) extends RandomAccessSeq[T] {
+
+ /** A paged sequence is constructed 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[T], Int, Int) => Int) = this(more, new Page[T](0), 0, UndeterminedEnd)
+
+ private var current: Page[T] = 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 apply(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
+ }
+
+ /** the subsequence from index `start' up to and excluding
+ * the minimum of index `end' and the length of the current sequence.
+ */
+ override def slice(_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 PagedSeq(more, f, s, e)
+ }
+
+ /** the subsequence from index `start' up to the
+ * length of the current sequence.
+ */
+ override def slice(start: Int) = slice(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[T](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 cachae for pointing to last page */
+ var later : Page[T] = 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 data = new Array[T](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[T] = {
+ if (later.next != null) later = later.next.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)
+ data(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[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/src/library/scala/runtime/RichString.scala b/src/library/scala/runtime/RichString.scala
index 192cf62ebb..412f2fd86c 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 CharSequence with RandomAccessSeq[Char] with Ordered[String] {
+final class RichString(val self: String) extends Proxy with RandomAccessSeq[Char] with Ordered[String] {
import RichString._
override def apply(n: Int) = self charAt n
override def length = self.length
@@ -74,11 +74,6 @@ final class RichString(val self: String) extends Proxy with CharSequence with Ra
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 = {
@@ -220,7 +215,7 @@ final class RichString(val self: String) extends Proxy with CharSequence with Ra
def toFloat: Float = java.lang.Float.parseFloat(self)
def toDouble: Double = java.lang.Double.parseDouble(self)
- override def toArray: Array[Char] = {
+ def toArray: Array[Char] = {
val result = new Array[Char](length)
self.getChars(0, length, result, 0)
result
diff --git a/src/library/scala/util/parsing/combinator/RegexParsers.scala b/src/library/scala/util/parsing/combinator/RegexParsers.scala
index 37b5f1d10c..49af37c8fc 100644
--- a/src/library/scala/util/parsing/combinator/RegexParsers.scala
+++ b/src/library/scala/util/parsing/combinator/RegexParsers.scala
@@ -13,6 +13,7 @@ package scala.util.parsing.combinator
import java.util.regex.Pattern
import scala.util.matching.Regex
import scala.util.parsing.input._
+import scala.collection.immutable.PagedSeq
trait RegexParsers extends Parsers {
@@ -22,9 +23,9 @@ trait RegexParsers extends Parsers {
def skipWhitespace = whiteSpace.toString.length > 0
- protected def handleWhiteSpace(source: CharSequence, offset: Int): Int =
+ protected def handleWhiteSpace(source: java.lang.CharSequence, offset: Int): Int =
if (skipWhitespace)
- (whiteSpace findPrefixMatchOf (source subSequence offset)) match {
+ (whiteSpace findPrefixMatchOf (source.subSequence(offset, source.length))) match {
case Some(matched) => offset + matched.end
case None => offset
}
@@ -39,7 +40,7 @@ trait RegexParsers extends Parsers {
val start = handleWhiteSpace(source, offset)
var i = 0
var j = start
- while (i < s.length && source.isDefinedAt(j) && s.charAt(i) == source.charAt(j)) {
+ while (i < s.length && j < source.length && s.charAt(i) == source.charAt(j)) {
i += 1
j += 1
}
@@ -56,7 +57,7 @@ trait RegexParsers extends Parsers {
val source = in.source
val offset = in.offset
val start = handleWhiteSpace(source, offset)
- (r findPrefixMatchOf (source subSequence start)) match {
+ (r findPrefixMatchOf (source.subSequence(start, source.length))) match {
case Some(matched) =>
Success(source.subSequence(start, start + matched.end).toString,
in.drop(start + matched.end - offset))
@@ -66,19 +67,27 @@ trait RegexParsers extends Parsers {
}
}
+ /** Parse some prefix of reader `in' with parser `p' */
+ def parse[T](p: Parser[T], in: Reader[Char]): ParseResult[T] =
+ p(in)
+
/** 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: java.lang.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)
+ def parse[T](p: Parser[T], in: java.io.Reader): ParseResult[T] =
+ p(new PagedSeqReader(PagedSeq.fromReader(in)))
- /** Parse all of character sequence `in' with parser `p' */
- def parseAll[T](p: Parser[T], in: CharSequence): ParseResult[T] =
+ /** Parse all of reader `in' with parser `p' */
+ def parseAll[T](p: Parser[T], in: Reader[Char]): 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] =
+ def parseAll[T](p: Parser[T], in: java.io.Reader): ParseResult[T] =
+ parse(phrase(p), in)
+
+ /** Parse all of character sequence `in' with parser `p' */
+ def parseAll[T](p: Parser[T], in: java.lang.CharSequence): ParseResult[T] =
parse(phrase(p), in)
}
diff --git a/src/library/scala/util/parsing/input/CharArrayReader.scala b/src/library/scala/util/parsing/input/CharArrayReader.scala
index 44e1b6eb6e..e8eef0e78c 100644
--- a/src/library/scala/util/parsing/input/CharArrayReader.scala
+++ b/src/library/scala/util/parsing/input/CharArrayReader.scala
@@ -32,7 +32,7 @@ object CharArrayReader {
* @author Martin Odersky, Adriaan Moors
*/
class CharArrayReader(chars: Array[Char], index: Int)
-extends CharSequenceReader(CharSequence.fromArray(chars), index) {
+extends CharSequenceReader(chars, index) {
def this(chars: Array[Char]) = this(chars, 0)
diff --git a/src/library/scala/util/parsing/input/CharSequenceReader.scala b/src/library/scala/util/parsing/input/CharSequenceReader.scala
index bf1ad6e244..4b06808889 100644
--- a/src/library/scala/util/parsing/input/CharSequenceReader.scala
+++ b/src/library/scala/util/parsing/input/CharSequenceReader.scala
@@ -26,19 +26,19 @@ object CharSequenceReader {
*
* @author Martin Odersky
*/
-class CharSequenceReader(override val source: CharSequence,
+class CharSequenceReader(override val source: java.lang.CharSequence,
override val offset: Int) extends Reader[Char] {
import CharSequenceReader._
/** Construct a <code>CharSequenceReader</code> with its first element at
* <code>source(0)</code> and position <code>(1,1)</code>.
*/
- def this(source: CharSequence) = this(source, 0)
+ def this(source: java.lang.CharSequence) = this(source, 0)
/** Returns the first element of the reader, or EofCh if reader is at its end
*/
def first =
- if (source.isDefinedAt(offset)) source(offset) else EofCh
+ if (offset < source.length) source.charAt(offset) else EofCh
/** Returns a CharSequenceReader consisting of all elements except the first
*
@@ -47,7 +47,7 @@ class CharSequenceReader(override val source: CharSequence,
* the rest of input.
*/
def rest: CharSequenceReader =
- if (source.isDefinedAt(offset)) new CharSequenceReader(source, offset + 1)
+ if (offset < source.length) new CharSequenceReader(source, offset + 1)
else this
/** The position of the first element in the reader
@@ -57,7 +57,7 @@ class CharSequenceReader(override val source: CharSequence,
/** true iff there are no more elements in this reader (except for trailing
* EofCh's)
*/
- def atEnd = !source.isDefinedAt(offset)
+ def atEnd = offset >= source.length
/** Returns an abstract reader consisting of all elements except the first
* <code>n</code> elements.
diff --git a/src/library/scala/util/parsing/input/PagedSeqReader.scala b/src/library/scala/util/parsing/input/PagedSeqReader.scala
new file mode 100755
index 0000000000..f6139219ab
--- /dev/null
+++ b/src/library/scala/util/parsing/input/PagedSeqReader.scala
@@ -0,0 +1,71 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id: PagedSeqReader.scala 14416 2008-03-19 01:17:25Z mihaylov $
+
+package scala.util.parsing.input
+
+import scala.collection.immutable.PagedSeq
+
+/** An object encapsulating basic character constants
+ *
+ * @author Martin Odersky, Adriaan Moors
+ */
+object PagedSeqReader {
+ final val EofCh = '\032'
+}
+
+/** A character array reader reads a stream of characters (keeping track of their positions)
+ * from an array.
+ *
+ * @param source the source sequence
+ * @param offset starting offset.
+ *
+ * @author Martin Odersky
+ */
+class PagedSeqReader(seq: PagedSeq[Char],
+ override val offset: Int) extends Reader[Char] {
+ import PagedSeqReader._
+
+ override lazy val source: java.lang.CharSequence = seq
+
+ /** Construct a <code>PagedSeqReader</code> with its first element at
+ * <code>source(0)</code> and position <code>(1,1)</code>.
+ */
+ def this(seq: PagedSeq[Char]) = this(seq, 0)
+
+ /** Returns the first element of the reader, or EofCh if reader is at its end
+ */
+ def first =
+ if (seq.isDefinedAt(offset)) seq(offset) else EofCh
+
+ /** Returns a PagedSeqReader consisting of all elements except the first
+ *
+ * @return If <code>atEnd</code> is <code>true</code>, the result will be
+ * <code>this'; otherwise, it's a <code>PagedSeqReader</code> containing
+ * the rest of input.
+ */
+ def rest: PagedSeqReader =
+ if (seq.isDefinedAt(offset)) new PagedSeqReader(seq, offset + 1)
+ else this
+
+ /** The position of the first element in the reader
+ */
+ def pos: Position = new OffsetPosition(source, offset)
+
+ /** true iff there are no more elements in this reader (except for trailing
+ * EofCh's)
+ */
+ def atEnd = !seq.isDefinedAt(offset)
+
+ /** Returns an abstract reader consisting of all elements except the first
+ * <code>n</code> elements.
+ */
+ override def drop(n: Int): PagedSeqReader =
+ new PagedSeqReader(seq, offset + n)
+}
diff --git a/src/library/scala/util/parsing/input/Reader.scala b/src/library/scala/util/parsing/input/Reader.scala
index 51cf7eeb47..d46173e416 100644
--- a/src/library/scala/util/parsing/input/Reader.scala
+++ b/src/library/scala/util/parsing/input/Reader.scala
@@ -18,15 +18,14 @@ package scala.util.parsing.input
*/
abstract class Reader[+T] {
- 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")
- }
+ /** If this is a reader over character sequences, the underlying char sequence
+ * If not, throws a <code>NoSuchMethodError</code> exception.
+ */
+ def source: java.lang.CharSequence =
+ throw new NoSuchMethodError("not a char sequence reader")
- 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")
- }
+ def offset: Int =
+ throw new NoSuchMethodError("not a char sequence reader")
/** Returns the first element of the reader
*/
diff --git a/src/library/scala/util/parsing/input/StreamReader.scala b/src/library/scala/util/parsing/input/StreamReader.scala
index f997590f18..a6fa1a7bcc 100644
--- a/src/library/scala/util/parsing/input/StreamReader.scala
+++ b/src/library/scala/util/parsing/input/StreamReader.scala
@@ -11,6 +11,7 @@
package scala.util.parsing.input
import java.io.BufferedReader
+import scala.collection.immutable.PagedSeq
/** An object to create a StreamReader from a <code>java.io.Reader</code>.
*
@@ -23,52 +24,52 @@ object StreamReader {
final val EofCh = '\032'
def apply(in: java.io.Reader): StreamReader = {
- new StreamReader(new LazyCharSequence(in), 0, 1)
+ new StreamReader(PagedSeq.fromReader(in), 0, 1)
}
}
-/** A character array reader reads a stream of characters (keeping track of
- * their positions) from an array.
+/** A StreamReader reads from a character sequence, typically created as a PagedSeq
+ * from a java.io.Reader
*
* NOTE:
* StreamReaders do not really fulfill the new contract for readers, which
* requires a `source' CharSequence representing the full input.
* Instead source is treated line by line.
- * As a consequence, regex matching cannot extend beyond a single lines
+ * As a consequence, regex matching cannot extend beyond a single line
* when a StreamReader are used for input.
*
- * @param bin the underlying java.io.BufferedReader
- * @param sourceLine the line at column `col' in the stream
- * @param line the 1-based line number of the character returned by `first'
- * @param column the 1-based column number of the character returned by `first'
+ * If you need to match regexes spanning several lines you should consider
+ * class <code>PagedSeqReader</code> instead.
*
- * @author Miles Sabin
+ * @author Miles Sabin
+ * @author Martin Odersky
*/
-sealed class StreamReader(source: CharSequence, offset: Int, lnum: Int) extends CharSequenceReader(source, offset) {
+sealed class StreamReader(seq: PagedSeq[Char], off: Int, lnum: Int) extends PagedSeqReader(seq, off) {
import StreamReader._
- 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)
+ override def rest: StreamReader =
+ if (off == seq.length) this
+ else if (seq(off) == '\n')
+ new StreamReader(seq.slice(off + 1), 0, lnum + 1)
+ else new StreamReader(seq, off + 1, lnum)
private def nextEol = {
- var i = offset
- while (i < source.length && source(i) != '\n' && source(i) != EofCh) i += 1
+ var i = off
+ while (i < seq.length && seq(i) != '\n' && seq(i) != EofCh) i += 1
i
}
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))
+ if (eolPos < off + n && eolPos < seq.length)
+ new StreamReader(seq.slice(eolPos + 1), 0, lnum + 1).drop(off + n - (eolPos + 1))
else
- new StreamReader(source, offset + n, lnum)
+ new StreamReader(seq, off + n, lnum)
}
override def pos: Position = new Position {
def line = lnum
- def column = offset + 1
- def lineContents = source.subSequence(0, nextEol).toString
+ def column = off + 1
+ def lineContents = seq.slice(0, nextEol).toString
}
}
diff --git a/test/files/neg/bug414.check b/test/files/neg/bug414.check
index 3396a803f1..ec23e26337 100644
--- a/test/files/neg/bug414.check
+++ b/test/files/neg/bug414.check
@@ -1,4 +1,4 @@
-bug414.scala:5: error: pattern type is incompatibe with expected type;
+bug414.scala:5: error: pattern type is incompatible with expected type;
found : object Empty
required: IntMap[a]
case Empty =>
diff --git a/test/files/run/caseclasses.scala b/test/files/run/caseclasses.scala
index b971cf3582..3afd7ee162 100644
--- a/test/files/run/caseclasses.scala
+++ b/test/files/run/caseclasses.scala
@@ -4,6 +4,9 @@ case class Bar
case class Baz(override val x: Int, y: Int) extends Foo(x)(y)
+abstract class Base
+abstract case class Abs(x: Int) extends Base
+
object M {
abstract case class C(x: String) {}
object C extends (String => C) {
@@ -16,6 +19,11 @@ object M {
object Test extends Application {
+ def Abs(x: Int) = new Abs(x * 2){}
+ Abs(2) match {
+ case Abs(4) => ;
+ }
+
def fn[a,b](x: a => b) = x;
val f = fn(Foo(1))
(f(2): AnyRef) match {
@@ -46,3 +54,4 @@ object Test extends Application {
}
}
+