summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2008-03-10 12:00:03 +0000
committerMartin Odersky <odersky@gmail.com>2008-03-10 12:00:03 +0000
commit83d3f475da9ab4db3bb35613639e55008b39b495 (patch)
tree9af5d7b4b8d8ffc79344599026a988caf7becaef
parent82953600481e3fa2238b897adb20d3fa7503c108 (diff)
downloadscala-83d3f475da9ab4db3bb35613639e55008b39b495.tar.gz
scala-83d3f475da9ab4db3bb35613639e55008b39b495.tar.bz2
scala-83d3f475da9ab4db3bb35613639e55008b39b495.zip
1.
2. Added * operator to RichString 3. changed zip in Array to accept arrays of different length 4. changed takeWhile/dropWhile in Array to yield Projections 5. Added Manifest types
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala90
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala91
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala51
-rw-r--r--src/library/scala/Array.scala28
-rwxr-xr-xsrc/library/scala/reflect/Manifest.scala22
-rw-r--r--src/library/scala/runtime/BoxedArray.scala23
-rw-r--r--src/library/scala/runtime/RichString.scala8
-rw-r--r--src/library/scala/util/parsing/combinator/Parsers.scala11
-rwxr-xr-xsrc/library/scala/util/parsing/combinator/RegexParsers.scala87
-rw-r--r--src/library/scala/util/parsing/combinator/lexical/Scanners.scala2
-rwxr-xr-xsrc/library/scala/util/parsing/combinator/testing/RegexTest.scala21
-rw-r--r--src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala2
-rw-r--r--src/library/scala/util/parsing/input/CharArrayPosition.scala2
-rw-r--r--src/library/scala/util/parsing/input/CharArrayReader.scala28
-rwxr-xr-xsrc/library/scala/util/parsing/input/CharArraySequence.scala37
-rwxr-xr-xsrc/library/scala/util/parsing/input/CharSequenceReader.scala79
-rwxr-xr-xsrc/library/scala/util/parsing/input/OffsetPosition.scala73
-rw-r--r--src/library/scala/util/parsing/input/Position.scala15
-rw-r--r--src/library/scala/util/parsing/input/Reader.scala23
-rwxr-xr-xsrc/library/scala/util/parsing/input/StreamReader.scala10
-rwxr-xr-xtest/files/pos/manifest1.scala20
-rw-r--r--test/pending/neg/t0513.scala6
25 files changed, 564 insertions, 175 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index f37a34ae74..772fdd59b4 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -199,6 +199,9 @@ abstract class TreeGen {
def mkAsInstanceOf(value: Tree, tpe: Type): Tree =
mkAsInstanceOf(value, tpe, global.phase.erasedTypes)
+ def mkClassOf(tp: Type): Tree =
+ Literal(Constant(tp)) setType Predef_classOfType(tp)
+
def mkCheckInit(tree: Tree): Tree = {
var tpe = tree.tpe
if (tpe == null && tree.hasSymbol) tpe = tree.symbol.tpe
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 2528181e0e..153f81d1c5 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -94,6 +94,8 @@ trait Definitions {
lazy val ClassfileAnnotationClass: Symbol = getClass("scala.ClassfileAnnotation")
lazy val StaticAnnotationClass: Symbol = getClass("scala.StaticAnnotation")
lazy val TypeConstraintClass: Symbol = getClass("scala.TypeConstraint")
+ lazy val ManifestClass: Symbol = getClass("scala.reflect.Manifest")
+ lazy val ManifestModule: Symbol = getModule("scala.reflect.Manifest")
var CodeClass: Symbol = _
var CodeModule: Symbol = _
@@ -110,7 +112,6 @@ trait Definitions {
lazy val RandomAccessSeqMutableClass: Symbol = getMember(getModule("scala.RandomAccessSeq"), nme.Mutable)
def Seq_length = getMember(SeqClass, nme.length)
-
lazy val ListClass: Symbol = getClass("scala.List")
def List_isEmpty = getMember(ListClass, nme.isEmpty)
def List_head = getMember(ListClass, nme.head)
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index 69b7448bf1..9caa664097 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -403,4 +403,94 @@ trait StdNames {
}
def encode(str: String): Name = newTermName(NameTransformer.encode(str))
+
+ abstract class SymbolNames {
+ val JavaLang : Name
+ val Object : Name
+ val Class : Name
+ val String : Name
+ val Throwable : Name
+ val NPException : Name // NullPointerException
+ val NLRException : Name = newTermName("scala.runtime.NonLocalReturnException")
+ val ValueType : Name
+ val Serializable : Name
+ val BeanProperty : Name
+ val Delegate : Name
+ val IOOBException: Name // IndexOutOfBoundsException
+ val Code : Name
+ val BoxedNumber : Name
+ val BoxedCharacter : Name
+ val BoxedBoolean : Name
+
+ import scala.collection.mutable.HashMap
+ val Boxed = new HashMap[Name, Name]
+ }
+
+ private abstract class JavaNames extends SymbolNames {
+ final val JavaLang = newTermName("java.lang")
+ final val Object = newTermName("java.lang.Object")
+ final val Class = newTermName("java.lang.Class")
+ final val String = newTermName("java.lang.String")
+ final val Throwable = newTermName("java.lang.Throwable")
+ final val NPException = newTermName("java.lang.NullPointerException")
+ final val ValueType = nme.NOSYMBOL
+ final val Delegate = nme.NOSYMBOL
+ final val IOOBException = newTermName("java.lang.IndexOutOfBoundsException")
+ final val BoxedNumber = newTermName("java.lang.Number")
+ final val BoxedCharacter = newTermName("java.lang.Character")
+ final val BoxedBoolean = newTermName("java.lang.Boolean")
+
+ Boxed += (nme.Boolean -> newTermName("java.lang.Boolean"))
+ Boxed += (nme.Byte -> newTermName("java.lang.Byte"))
+ Boxed += (nme.Char -> newTermName("java.lang.Character"))
+ Boxed += (nme.Short -> newTermName("java.lang.Short"))
+ Boxed += (nme.Int -> newTermName("java.lang.Integer"))
+ Boxed += (nme.Long -> newTermName("java.lang.Long"))
+ Boxed += (nme.Float -> newTermName("java.lang.Float"))
+ Boxed += (nme.Double -> newTermName("java.lang.Double"))
+ }
+
+ private class MSILNames extends SymbolNames {
+ final val JavaLang = newTermName("System")
+ final val Object = newTermName("System.Object")
+ final val Class = newTermName("System.Type")
+ final val String = newTermName("System.String")
+ final val Throwable = newTermName("System.Exception")
+ final val NPException = newTermName("System.NullReferenceException")
+ final val ValueType = newTermName("System.ValueType")
+ final val Serializable = nme.NOSYMBOL
+ final val BeanProperty = nme.NOSYMBOL
+ final val Delegate = newTermName("System.MulticastDelegate")
+ final val IOOBException = newTermName("System.IndexOutOfRangeException")
+ final val Code = nme.NOSYMBOL
+ final val BoxedNumber = newTermName("System.IConvertible")
+ final val BoxedCharacter = newTermName("System.IConvertible")
+ final val BoxedBoolean = newTermName("System.IConvertible")
+
+ Boxed += (nme.Boolean -> newTermName("System.Boolean"))
+ Boxed += (nme.Byte -> newTermName("System.Byte"))
+ Boxed += (nme.Char -> newTermName("System.Char"))
+ Boxed += (nme.Short -> newTermName("System.Int16"))
+ Boxed += (nme.Int -> newTermName("System.Int32"))
+ Boxed += (nme.Long -> newTermName("System.Int64"))
+ Boxed += (nme.Float -> newTermName("System.Single"))
+ Boxed += (nme.Double -> newTermName("System.Double"))
+ }
+
+ private class J2SENames extends JavaNames {
+ final val Serializable = newTermName("java.io.Serializable")
+ final val BeanProperty = newTermName("scala.reflect.BeanProperty")
+ final val Code = newTermName("scala.reflect.Code")
+ }
+
+ private class CLDCNames extends JavaNames {
+ final val Serializable = nme.NOSYMBOL
+ final val BeanProperty = nme.NOSYMBOL
+ final val Code = nme.NOSYMBOL
+ }
+
+ val sn: SymbolNames =
+ if (forMSIL) new MSILNames
+ else if (forCLDC) new CLDCNames
+ else new J2SENames
}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
index 1e3dd8aaa9..efc270db6f 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -116,95 +116,4 @@ abstract class SymbolTable extends Names
/** The phase which has given index as identifier */
val phaseWithId: Array[Phase]
-
- abstract class SymbolNames {
- val JavaLang : Name
- val Object : Name
- val Class : Name
- val String : Name
- val Throwable : Name
- val NPException : Name // NullPointerException
- val NLRException : Name = newTermName("scala.runtime.NonLocalReturnException")
- val ValueType : Name
- val Serializable : Name
- val BeanProperty : Name
- val Delegate : Name
- val IOOBException: Name // IndexOutOfBoundsException
- val Code : Name
- val BoxedNumber : Name
- val BoxedCharacter : Name
- val BoxedBoolean : Name
-
- import scala.collection.mutable.HashMap
- val Boxed = new HashMap[Name, Name]
- }
-
- private abstract class JavaNames extends SymbolNames {
- final val JavaLang = newTermName("java.lang")
- final val Object = newTermName("java.lang.Object")
- final val Class = newTermName("java.lang.Class")
- final val String = newTermName("java.lang.String")
- final val Throwable = newTermName("java.lang.Throwable")
- final val NPException = newTermName("java.lang.NullPointerException")
- final val ValueType = nme.NOSYMBOL
- final val Delegate = nme.NOSYMBOL
- final val IOOBException = newTermName("java.lang.IndexOutOfBoundsException")
- final val BoxedNumber = newTermName("java.lang.Number")
- final val BoxedCharacter = newTermName("java.lang.Character")
- final val BoxedBoolean = newTermName("java.lang.Boolean")
-
- Boxed += (nme.Boolean -> newTermName("java.lang.Boolean"))
- Boxed += (nme.Byte -> newTermName("java.lang.Byte"))
- Boxed += (nme.Char -> newTermName("java.lang.Character"))
- Boxed += (nme.Short -> newTermName("java.lang.Short"))
- Boxed += (nme.Int -> newTermName("java.lang.Integer"))
- Boxed += (nme.Long -> newTermName("java.lang.Long"))
- Boxed += (nme.Float -> newTermName("java.lang.Float"))
- Boxed += (nme.Double -> newTermName("java.lang.Double"))
- }
-
- private class MSILNames extends SymbolNames {
- final val JavaLang = newTermName("System")
- final val Object = newTermName("System.Object")
- final val Class = newTermName("System.Type")
- final val String = newTermName("System.String")
- final val Throwable = newTermName("System.Exception")
- final val NPException = newTermName("System.NullReferenceException")
- final val ValueType = newTermName("System.ValueType")
- final val Serializable = nme.NOSYMBOL
- final val BeanProperty = nme.NOSYMBOL
- final val Delegate = newTermName("System.MulticastDelegate")
- final val IOOBException = newTermName("System.IndexOutOfRangeException")
- final val Code = nme.NOSYMBOL
- final val BoxedNumber = newTermName("System.IConvertible")
- final val BoxedCharacter = newTermName("System.IConvertible")
- final val BoxedBoolean = newTermName("System.IConvertible")
-
- Boxed += (nme.Boolean -> newTermName("System.Boolean"))
- Boxed += (nme.Byte -> newTermName("System.Byte"))
- Boxed += (nme.Char -> newTermName("System.Char"))
- Boxed += (nme.Short -> newTermName("System.Int16"))
- Boxed += (nme.Int -> newTermName("System.Int32"))
- Boxed += (nme.Long -> newTermName("System.Int64"))
- Boxed += (nme.Float -> newTermName("System.Single"))
- Boxed += (nme.Double -> newTermName("System.Double"))
- }
-
- private class J2SENames extends JavaNames {
- final val Serializable = newTermName("java.io.Serializable")
- final val BeanProperty = newTermName("scala.reflect.BeanProperty")
- final val Code = newTermName("scala.reflect.Code")
- }
-
- private class CLDCNames extends JavaNames {
- final val Serializable = nme.NOSYMBOL
- final val BeanProperty = nme.NOSYMBOL
- final val Code = nme.NOSYMBOL
- }
-
- val sn: SymbolNames =
- if (forMSIL) new MSILNames
- else if (forCLDC) new CLDCNames
- else new J2SENames
-
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 4ede3dec3b..50fbc23c3d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -16,8 +16,8 @@ trait Analyzer extends AnyRef
with Variances
with EtaExpansion
with SyntheticMethods
- with Unapplies {
-
+ with Unapplies
+{
val global : Global
import global._
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index e7d18f5c6e..b5a39f3c8d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2385,8 +2385,7 @@ trait Typers { self: Analyzer =>
checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "")
if (fun.symbol == Predef_classOf) {
checkClassType(args.head, true)
- Literal(Constant(targs.head)) setPos tree.pos setType Predef_classOfType(targs.head)
- // @M: targs.head.normalize is not necessary --> toTypeKind eventually normalizes the type
+ atPos(tree.pos) { gen.mkClassOf(targs.head) }
} else {
if (phase.id <= currentRun.typerPhase.id &&
fun.symbol == Any_isInstanceOf && !targs.isEmpty)
@@ -3475,13 +3474,61 @@ trait Typers { self: Analyzer =>
List()
}
+ def implicitManifest(pt: Type): Tree = pt match {
+ case TypeRef(_, ManifestClass, List(arg)) => manifestOfType(pos, arg)
+ case _ => EmptyTree
+ }
+
var tree = searchImplicit(context.implicitss, true)
if (tree == EmptyTree) tree = searchImplicit(implicitsOfType(pt), false)
+ if (tree == EmptyTree) tree = implicitManifest(pt)
if (util.Statistics.enabled)
impltime = impltime + currentTime - startTime
tree
}
+ def manifestOfType(pos: Position, tp: Type): Tree = {
+ def mkManifest(name: String, args: Tree*): Tree =
+ if (args contains EmptyTree) EmptyTree
+ else
+ typed {
+ atPos(pos) {
+ val fn = TypeApply(
+ Select(gen.mkAttributedRef(ManifestModule), name),
+ List(TypeTree(tp)))
+ if (args.isEmpty) fn else Apply(fn, args.toList)
+ }
+ }
+ def findManifest(tp: Type): Tree =
+ inferImplicit(pos, appliedType(ManifestClass.typeConstructor, List(tp)), true)
+ tp.normalize match {
+ case ThisType(_) | SingleType(_, _) =>
+ mkManifest("singleType", gen.mkAttributedQualifier(tp))
+ case ConstantType(value) =>
+ findManifest(tp.deconst)
+ case TypeRef(pre, sym, args) =>
+ if (sym.isClass) {
+ val suffix = gen.mkClassOf(tp) :: (args map findManifest)
+ mkManifest(
+ "classType",
+ (if ((pre eq NoPrefix) || pre.typeSymbol.isStaticOwner) suffix
+ else findManifest(pre) :: suffix): _*)
+ } else if (sym.isTypeParameterOrSkolem) {
+ EmptyTree // a manifest should have been found by normal searchImplicit
+ } else {
+ mkManifest(
+ "abstractType",
+ findManifest(pre) :: Literal(sym.name.toString) :: (args map findManifest): _*)
+ }
+ case RefinedType(parents, decls) =>
+ // refinement is not generated yet
+ if (parents.length == 1) findManifest(parents.head)
+ else mkManifest("intersectionType", parents map findManifest: _*)
+ case _ =>
+ EmptyTree
+ }
+ }
+
def applyImplicitArgs(tree: Tree): Tree = tree.tpe match {
case MethodType(formals, _) =>
def implicitArg(pt: Type) = {
diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala
index bafe0ac58e..b3f08c5ef8 100644
--- a/src/library/scala/Array.scala
+++ b/src/library/scala/Array.scala
@@ -189,6 +189,14 @@ object Array {
override def force : Array[A] = toArray
override def drop( from: Int) = slice(from, length)
override def take(until: Int) = slice(0, until)
+ override def dropWhile(p: A => Boolean) = {
+ val c = length + 1
+ drop((findIndexOf(!p(_)) + c) % c)
+ }
+ override def takeWhile(p: A => Boolean) = {
+ val c = length + 1
+ take((findIndexOf(!p(_)) + c) % c)
+ }
override def slice(from0 : Int, until0 : Int) : Projection[A] = new RandomAccessSeq.MutableSlice[A] with Projection[A] {
override def from = from0
override def until = until0
@@ -214,6 +222,8 @@ object Array {
override def slice(from : Int, until : Int) : Projection[A] = projection.slice(from, until)
override def take(until : Int) : Projection[A] = projection.take(until)
override def drop(from : Int) : Projection[A] = projection.drop(from)
+ override def dropWhile(p: A => Boolean) = projection.dropWhile(p)
+ override def takeWhile(p: A => Boolean) = projection.takeWhile(p)
override def reverse = projection.reverse
override def force = asInstanceOf[Array[A]]
}
@@ -328,24 +338,6 @@ final class Array[A](_length: Int) extends Array.Array0[A] {
*/
override def filter(p: A => Boolean): Array[A] = throw new Error()
- /** Returns the longest prefix of this array whose elements satisfy
- * the predicate <code>p</code>.
- *
- * @param p the test predicate.
- * @return the longest prefix of this array whose elements satisfy
- * the predicate <code>p</code>.
- */
- override def takeWhile(p: A => Boolean): Array[A] = throw new Error()
-
- /** Returns the longest suffix of this array whose first element
- * does not satisfy the predicate <code>p</code>.
- *
- * @param p the test predicate.
- * @return the longest suffix of the array whose first element
- * does not satisfy the predicate <code>p</code>.
- */
- override def dropWhile(p: A => Boolean): Array[A] = throw new Error()
-
/** Returns an array consisting of all elements of this array followed
* by all elements of the argument iterable.
*/
diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala
new file mode 100755
index 0000000000..ee4d70ebda
--- /dev/null
+++ b/src/library/scala/reflect/Manifest.scala
@@ -0,0 +1,22 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2002-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+package scala.reflect
+
+object Manifest {
+ def singleType[T](value: Any): Manifest[T] = null
+ def classType[T](clazz: Predef.Class[_]): Manifest[T] = null
+ def classType[T](clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = null
+ def classType[T](prefix: Manifest[_], clazz: Predef.Class[_]): Manifest[T] = null
+ def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = null
+ def abstractType[T](prefix: Manifest[_], name: String): Manifest[T] = null
+ def abstractType[T](prefix: Manifest[_], name: String, args: Manifest[_]*): Manifest[T] = null
+ def intersectionType[T](parents: Manifest[_]*): Manifest[T] = null
+}
+
+abstract class Manifest[T]
+
diff --git a/src/library/scala/runtime/BoxedArray.scala b/src/library/scala/runtime/BoxedArray.scala
index f3193ec017..ea0d7c654d 100644
--- a/src/library/scala/runtime/BoxedArray.scala
+++ b/src/library/scala/runtime/BoxedArray.scala
@@ -98,23 +98,23 @@ abstract class BoxedArray extends Array.Array0[Any] {
final override def ++[b >: Any](that: Iterable[b]): Array[b] = super.++(that).toArray
- final def zip[b](that: Array[b]): Array[Tuple2[Any,b]] = {
- val len = length min that.length
- val result = new Array[Tuple2[Any,b]](len)
+ final def zip[b](that: Array[b]): Array[(Any,b)] = {
+ val len = this.length min that.length
+ val result = new Array[(Any,b)](len)
var i = 0
while (i < len) {
- result(i) = new Tuple2(this(i), that(i))
+ result(i) = (this(i), that(i))
i += 1
}
result
}
- final def zipWithIndex: Array[Tuple2[Any,Int]] = {
+ final def zipWithIndex: Array[(Any,Int)] = {
val len = length
- val result = new Array[Tuple2[Any,Int]](len)
+ val result = new Array[(Any,Int)](len)
var i = 0
while (i < len) {
- result(i) = new Tuple2(this(i), i)
+ result(i) = (this(i), i)
i += 1
}
result
@@ -123,15 +123,6 @@ abstract class BoxedArray extends Array.Array0[Any] {
/** Returns an array that contains all indices of this array */
def indices: Array[Int] = Array.range(0, length)
- override def takeWhile(p: Any => Boolean) = {
- val c = length + 1
- take((findIndexOf(!p(_)) + c) % c)
- }
- override def dropWhile(p: Any => Boolean) = {
- val c = length + 1
- drop((findIndexOf(!p(_)) + c) % c)
- }
-
final def deepToString() = deepMkString(stringPrefix + "(", ",", ")")
final def deepMkString(start: String, sep: String, end: String): String = {
diff --git a/src/library/scala/runtime/RichString.scala b/src/library/scala/runtime/RichString.scala
index afd80afb66..8e6bca4ba5 100644
--- a/src/library/scala/runtime/RichString.scala
+++ b/src/library/scala/runtime/RichString.scala
@@ -74,6 +74,14 @@ final class RichString(val self: String) extends Proxy with RandomAccessSeq[Char
new RichString(buf.toString)
}
+ /** return n times the current string
+ */
+ def * (n: Int): String = {
+ val buf = new StringBuffer
+ for (i <- 0 until n) buf append self
+ buf.toString
+ }
+
override def compare(other: String) = self compareTo other
private def isLineBreak(c: Char) = c == LF || c == FF
diff --git a/src/library/scala/util/parsing/combinator/Parsers.scala b/src/library/scala/util/parsing/combinator/Parsers.scala
index b566375280..450fc73d86 100644
--- a/src/library/scala/util/parsing/combinator/Parsers.scala
+++ b/src/library/scala/util/parsing/combinator/Parsers.scala
@@ -715,9 +715,14 @@ trait Parsers {
def phrase[T](p: Parser[T]) = new Parser[T] {
lastNoSuccess = null
def apply(in: Input) = p(in) match {
- case s @ Success(out, in1) if in1.atEnd => s
- case s @ Success(out, in1) => Failure("end of input expected", in1)
- case f : NoSuccess => lastNoSuccess
+ case s @ Success(out, in1) =>
+ if (in1.atEnd)
+ s
+ else if (lastNoSuccess == null || lastNoSuccess.next.pos < in1.pos)
+ Failure("end of input expected", in1)
+ else
+ lastNoSuccess
+ case _ => lastNoSuccess
}
}
diff --git a/src/library/scala/util/parsing/combinator/RegexParsers.scala b/src/library/scala/util/parsing/combinator/RegexParsers.scala
new file mode 100755
index 0000000000..6d42bb2794
--- /dev/null
+++ b/src/library/scala/util/parsing/combinator/RegexParsers.scala
@@ -0,0 +1,87 @@
+/* __ *\
+** ________ ___ / / ___ 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
+
+import java.util.regex._
+import scala.util.parsing.input.CharSequenceReader
+
+trait RegexParsers extends Parsers {
+
+ type Elem = Char
+
+ var skipWhitespace = true
+
+ private val whiteSpacePat = Pattern compile """\s+"""
+
+ 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
+ }
+
+ /** A parser that matches a literal string */
+ implicit def literal(s: String): Parser[String] = new Parser[String] {
+ def apply(in: Input) = {
+ val source = in.source
+ val offset = in.offset
+ val start = handleWhiteSpace(source, offset)
+ var i = 0
+ var j = start
+ while (i < s.length && j < source.length && 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))
+ }
+ }
+
+ /** A parser that matches a regex string */
+ def regex(s: String): Parser[String] = new Parser[String] {
+ private val pattern = Pattern.compile(s)
+ def apply(in: Input) = {
+ val source = in.source
+ val offset = in.offset
+ val start = handleWhiteSpace(source, offset)
+ val pm = 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 `"+s+"' expected", in.drop(start - offset))
+ }
+ }
+
+ /** A helper class to turn strings into regexes */
+ class PreRegex(s: String) {
+ def r: Parser[String] = regex(s)
+ }
+
+ /** An implicit definition which lets you follow a string with `.r', turning
+ * it into a regex parser. E.g.
+ *
+ * """A\w*""".r is a regex parser for identifiers starting with `A'.
+ */
+ implicit def mkPreRegex(s: String) = new PreRegex(s)
+
+ /** Parse some prefix of character sequence `in' with parser `p' */
+ def parse[T](p: Parser[T])(in: CharSequence): ParseResult[T] =
+ p(new CharSequenceReader(in))
+
+ /** Parse all of character sequence `in' with parser `p' */
+ def parseAll[T](p: Parser[T])(in: CharSequence): 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 8b9e7724b7..d4f3103a71 100644
--- a/src/library/scala/util/parsing/combinator/lexical/Scanners.scala
+++ b/src/library/scala/util/parsing/combinator/lexical/Scanners.scala
@@ -66,6 +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
def first = tok
def rest = new Scanner(rest2)
def pos = rest1.pos
diff --git a/src/library/scala/util/parsing/combinator/testing/RegexTest.scala b/src/library/scala/util/parsing/combinator/testing/RegexTest.scala
new file mode 100755
index 0000000000..a1356f8afe
--- /dev/null
+++ b/src/library/scala/util/parsing/combinator/testing/RegexTest.scala
@@ -0,0 +1,21 @@
+package test
+
+import scala.util.parsing.combinator._
+import scala.util.parsing.input._
+
+case class Ident(s: String)
+case class Number(n: Int)
+case class Str(s: String)
+
+object RegexTest extends RegexParsers {
+ val ident: Parser[Any] = """[a-zA-Z_]\w*""".r ^^ (s => Ident(s))
+ val number: Parser[Any] = """\d\d*""".r ^^ (s => Number(s.toInt))
+ val string: Parser[Any] = "\".*\"".r ^^ (s => Str(s.substring(1, s.length - 1)))
+ val parser = (ident | number | string)*
+
+ def main(args: Array[String]) = {
+ val in = args mkString " "
+ println("\nin : "+in)
+ println(phrase[Any](parser)(new CharSequenceReader(in)))
+ }
+}
diff --git a/src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala b/src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala
index 2256c76d62..d4479d8045 100644
--- a/src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala
+++ b/src/library/scala/util/parsing/combinatorold/lexical/Scanners.scala
@@ -66,6 +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
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 c3d9f6ea62..8d63b12332 100644
--- a/src/library/scala/util/parsing/input/CharArrayPosition.scala
+++ b/src/library/scala/util/parsing/input/CharArrayPosition.scala
@@ -18,7 +18,9 @@ package scala.util.parsing.input
* @param columm The column number of the position (1-based)
*
* @author Martin Odersky, Adriaan Moors
+ * @deprecated; use OffsetPosition instead
*/
+@deprecated
class CharArrayPosition(val source: Array[Char], val line: Int, val column: Int) extends Position {
// TODO: this could be implemented more high-level:
diff --git a/src/library/scala/util/parsing/input/CharArrayReader.scala b/src/library/scala/util/parsing/input/CharArrayReader.scala
index f1f3240e19..b7c576c631 100644
--- a/src/library/scala/util/parsing/input/CharArrayReader.scala
+++ b/src/library/scala/util/parsing/input/CharArrayReader.scala
@@ -29,31 +29,9 @@ object CharArrayReader {
*
* @author Martin Odersky, Adriaan Moors
*/
-class CharArrayReader(source: Array[Char], index: Int, line: Int, column: Int) extends Reader[Char] {
- import CharArrayReader._
+class CharArrayReader(chars: Array[Char], index: Int)
+extends CharSequenceReader(new CharArraySequence(chars), index) {
- /** Construct a <code>CharArrayReader</code> with its first element at
- * <code>source(0)</code> and position <code>(1,1)</code>.
- */
- def this(source: Array[Char]) = this(source, 0, 1, 1)
+ def this(chars: Array[Char]) = this(chars, 0)
- private var i = index
- if (i + 1 < source.length && source(i) == CR && source(i + 1) == '\n') i += 1
-
- // see `first' in `Reader'
- def first = if (i == source.length) EofCh else source(i)
-
- // see `rest' in `Reader'
- def rest: CharArrayReader = {
- val ch = first
- if (ch == EofCh) this
- else if (ch == '\n') new CharArrayReader(source, i + 1, line + 1, 1)
- else new CharArrayReader(source, i + 1, line, column + 1)
- }
-
- // see `pos' in `Reader'
- def pos: Position = new CharArrayPosition(source, line, column)
-
- // see `atEnd' in `Reader'
- def atEnd = i == source.length
}
diff --git a/src/library/scala/util/parsing/input/CharArraySequence.scala b/src/library/scala/util/parsing/input/CharArraySequence.scala
new file mode 100755
index 0000000000..9acca84df2
--- /dev/null
+++ b/src/library/scala/util/parsing/input/CharArraySequence.scala
@@ -0,0 +1,37 @@
+/* __ *\
+** ________ ___ / / ___ 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
new file mode 100755
index 0000000000..453a808f08
--- /dev/null
+++ b/src/library/scala/util/parsing/input/CharSequenceReader.scala
@@ -0,0 +1,79 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+// $Id: StringReader.scala 12268 2007-07-11 13:45:53Z michelou $
+
+package scala.util.parsing.input
+
+/** An object encapsulating basic character constants
+ *
+ * @author Martin Odersky, Adriaan Moors
+ */
+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.
+ *
+ * @author Martin Odersky
+ */
+class CharSequenceReader(val source: CharSequence, index: 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)
+
+ /** 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)
+
+ /** Returns a CharSequenceReader 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>CharSequenceReader</code> containing
+ * the rest of input.
+ */
+ def rest: CharSequenceReader =
+ if (offset == source.length) this
+ else new CharSequenceReader(source, offset + 1)
+
+ /** 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 = offset == source.length
+
+ /** 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)
+}
diff --git a/src/library/scala/util/parsing/input/OffsetPosition.scala b/src/library/scala/util/parsing/input/OffsetPosition.scala
new file mode 100755
index 0000000000..a29e195455
--- /dev/null
+++ b/src/library/scala/util/parsing/input/OffsetPosition.scala
@@ -0,0 +1,73 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+package scala.util.parsing.input
+
+import collection.mutable.ArrayBuffer
+
+/** <p>
+ * <code>OffsetPosition</code> is a standard class for positions
+ * represented as offsets into a source ``document''.
+ * @param source The source document
+ * @param offset The offset indicating the position
+ *
+ * @author Martin Odersky
+ */
+case class OffsetPosition(source: CharSequence, offset: Int) extends Position {
+
+ /** An index that contains all line starts, including first line, and eof */
+ private lazy val index: Array[Int] = {
+ var lineStarts = new ArrayBuffer[Int]
+ lineStarts += 0
+ for (i <- 0 until source.length)
+ if (source.charAt(i) == '\n') lineStarts += (i + 1)
+ lineStarts += source.length
+ lineStarts.toArray
+ }
+
+ /** The line number referred to by the position; line numbers start at 1 */
+ def line: Int = {
+ var lo = 0
+ var hi = index.length - 1
+ while (lo + 1 < hi) {
+ val mid = (hi + lo) / 2
+ if (offset < index(mid)) hi = mid
+ else lo = mid
+ }
+ lo + 1
+ }
+
+ /** The column number referred to by the position; column numbers start at 1 */
+ def column: Int = offset - index(line - 1) + 1
+
+ /** The contents of the line numbered `lnum' (must not contain a new-line character).
+ *
+ * @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
+
+ /** Returns a string representation of the `Position', of the form `line.column' */
+ override def toString = line+"."+column
+
+ /** Compare this position to another, by first comparing their line numbers,
+ * and then -- if necessary -- using the columns to break a tie.
+ *
+ * @param `that' a `Position' to compare to this `Position'
+ * @return true if this position's line or (in case of a tie wrt. line numbers)
+ * its column is smaller than the corresponding components of `that'
+ */
+ override def <(that: Position) = that match {
+ case OffsetPosition(_, that_offset) =>
+ this.offset < that_offset
+ case _ =>
+ this.line < that.line ||
+ this.line == that.line && this.column < that.column
+ }
+}
diff --git a/src/library/scala/util/parsing/input/Position.scala b/src/library/scala/util/parsing/input/Position.scala
index 1be14a1211..64d2ecf3a1 100644
--- a/src/library/scala/util/parsing/input/Position.scala
+++ b/src/library/scala/util/parsing/input/Position.scala
@@ -9,7 +9,7 @@
package scala.util.parsing.input
/** <p>
- * <code>Position</code> is the base class for objects describing a
+ * <code>Position</code> is the base trait for objects describing a
* position in a ``document''.
* </p>
* <p>
@@ -53,18 +53,7 @@ trait Position {
*<pre> List(this, is, a, line, from, the, document)
* ^</pre>
*/
- def longString = lineContents(line)+"\n"+List.toString(List.make(column-1, ' '))+"^"
-/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- TODO: it would be nicer to be able to write (' '*column-1)
- --> add * method to scala.runtime.RichChar?
- class RichChar { ...
- /** Returns a string that consists of `n' occurrences of this character. */
- def *(n: int) = {
- val chars = new StringBuffer
- for (val i <- 1 until n) chars append this
- chars.toString
- }
- }*/
+ def longString = lineContents(line)+"\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 3a1021bbd6..f9d7115113 100644
--- a/src/library/scala/util/parsing/input/Reader.scala
+++ b/src/library/scala/util/parsing/input/Reader.scala
@@ -17,7 +17,13 @@ package scala.util.parsing.input
*/
abstract class Reader[+T] {
- /** Returns the first element of the stream
+ /** The source character sequence for this reader */
+ def source: CharSequence
+
+ /** The current index into source */
+ def offset: Int
+
+ /** Returns the first element of the reader
*/
def first: T
@@ -29,12 +35,21 @@ abstract class Reader[+T] {
*/
def rest: Reader[T]
- /** The position of the first element in the stream
+ /** Returns an abstract reader consisting of all elements except the first
+ * <code>n</code> elements.
+ */
+ def drop(n: Int): Reader[T] = {
+ var r: Reader[T] = this
+ var cnt = n
+ while (cnt > 0) r = r.rest
+ r
+ }
+
+ /** The position of the first element in the reader
*/
def pos: Position
- /** Whether there are any more elements in this reader besides the first.
- * (i.e., whether calling `rest' will yield a `Reader' with more elements)
+ /** true iff there are no more elements in this reader
*/
def atEnd: Boolean
}
diff --git a/src/library/scala/util/parsing/input/StreamReader.scala b/src/library/scala/util/parsing/input/StreamReader.scala
index 9522e66650..bad859d4c0 100755
--- a/src/library/scala/util/parsing/input/StreamReader.scala
+++ b/src/library/scala/util/parsing/input/StreamReader.scala
@@ -32,6 +32,13 @@ object StreamReader {
/** A character array reader reads a stream of characters (keeping track of
* their positions) from an array.
*
+ * 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
+ * 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'
@@ -43,6 +50,9 @@ sealed class StreamReader private (bin: BufferedReader, sourceLine: String, ln:
extends Reader[Char] {
import StreamReader._
+ def source: CharSequence = sourceLine
+ def offset: Int = col-1
+
def first =
if (sourceLine == null)
EofCh
diff --git a/test/files/pos/manifest1.scala b/test/files/pos/manifest1.scala
new file mode 100755
index 0000000000..4d3b3bfa48
--- /dev/null
+++ b/test/files/pos/manifest1.scala
@@ -0,0 +1,20 @@
+import scala.reflect.Manifest
+
+object Test {
+ def foo[T](x: T)(implicit m: Manifest[T]) {
+ foo(List(x))
+ }
+ foo(1)
+ foo("abc")
+ foo(List(1, 2, 3))
+ val x: List[Int] with Ordered[List[Int]] = null
+ foo(x)
+ foo[x.type](x)
+ abstract class C { type T = String; val x: T }
+ val c = new C { val x = "abc" }
+ foo(c.x)
+ abstract class D { type T; val x: T }
+ val d: D = new D { type T = String; val x = "x" }
+ foo(d.x)
+
+}
diff --git a/test/pending/neg/t0513.scala b/test/pending/neg/t0513.scala
new file mode 100644
index 0000000000..0082b0e563
--- /dev/null
+++ b/test/pending/neg/t0513.scala
@@ -0,0 +1,6 @@
+object Test {
+ case class Y[T1, T2 <: T1]
+ //val test = Y[Nothing, Int] // Compiler error
+ case class Test[T]
+ val test2 = Test[Y[Nothing, Int]] // No error
+}