From 13b3d06f82c4f893dfc2710203bd64798fc73a99 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 25 Nov 2009 18:16:49 +0000 Subject: Working on scala.runtime. and falling out of sync with StringLike. Made a method in MethodCache verifiably tail-recursive. --- .../tools/nsc/ast/parser/SymbolicXMLBuilder.scala | 6 +- src/library/scala/runtime/MethodCache.scala | 28 ++- src/library/scala/runtime/RichString.scala | 261 --------------------- 3 files changed, 20 insertions(+), 275 deletions(-) delete mode 100644 src/library/scala/runtime/RichString.scala diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index 03f3053edc..51c937dd7f 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -57,11 +57,7 @@ abstract class SymbolicXMLBuilder(p: Parsers#Parser, preserveWS: Boolean) // convenience methods private def LL[A](x: A*): List[List[A]] = List(List(x:_*)) - private def const(x: Any) = x match { - case s: runtime.RichString => Literal(Constant(s.toString)) // not our finest hour - case s: collection.immutable.StringLike[_] => Literal(Constant(s.toString)) // not our finest hour - case _ => Literal(Constant(x)) - } + private def const(x: Any) = Literal(Constant(x)) private def wild = Ident(nme.WILDCARD) private def wildStar = Ident(nme.WILDCARD_STAR.toTypeName) private def _scala(name: Name) = Select(Select(Ident(nme.ROOTPKG), nme.scala_), name) diff --git a/src/library/scala/runtime/MethodCache.scala b/src/library/scala/runtime/MethodCache.scala index b4c31f9938..83528a4d00 100644 --- a/src/library/scala/runtime/MethodCache.scala +++ b/src/library/scala/runtime/MethodCache.scala @@ -14,6 +14,8 @@ package scala.runtime import java.lang.reflect.{ Method => JMethod } import java.lang.{ Class => JClass } +import scala.annotation.tailrec + /** An element of a polymorphic object cache. * This class is refered to by the CleanUp phase. Each PolyMethodCache chain * must only relate to one method as PolyMethodCache does not identify @@ -59,16 +61,24 @@ final class PolyMethodCache( private[this] val complexity: Int ) extends MethodCache { - def find(forReceiver: JClass[_]): JMethod = - if (forReceiver eq receiver) - return method - else - return next.find(forReceiver) // tail call is optimised, confirm with -Ylog:tailcalls + /** To achieve tail recursion this must be a separate method + * from find, because the type of next is not PolyMethodCache. + */ + @tailrec private def findInternal(forReceiver: JClass[_]): JMethod = + if (forReceiver eq receiver) method + else next match { + case x: PolyMethodCache => x findInternal forReceiver + case _ => next find forReceiver + } + + def find(forReceiver: JClass[_]): JMethod = findInternal(forReceiver) + + // TODO: come up with a more realistic number + final private val MaxComplexity = 160 def add(forReceiver: JClass[_], forMethod: JMethod): MethodCache = - if (complexity < 160) // TODO: come up with a more realistic number - return new PolyMethodCache(this, forReceiver, forMethod, complexity + 1) + if (complexity < MaxComplexity) + new PolyMethodCache(this, forReceiver, forMethod, complexity + 1) else - return new MegaMethodCache(forMethod.getName, forMethod.getParameterTypes) - + new MegaMethodCache(forMethod.getName, forMethod.getParameterTypes) } diff --git a/src/library/scala/runtime/RichString.scala b/src/library/scala/runtime/RichString.scala deleted file mode 100644 index a1058cf979..0000000000 --- a/src/library/scala/runtime/RichString.scala +++ /dev/null @@ -1,261 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2009, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -// $Id$ - - -package scala.runtime - -import scala.util.matching.Regex -import collection.generic._ -import collection.IndexedSeqLike -import collection.immutable.IndexedSeq -import collection.mutable.{Builder, StringBuilder} - -object RichString { - - def newBuilder: Builder[Char, RichString] = new StringBuilder() mapResult (new RichString(_)) - implicit def canBuildFrom: CanBuildFrom[RichString, Char, RichString] = - new CanBuildFrom[RichString, Char, RichString] { - def apply(from: RichString) = newBuilder - def apply() = newBuilder - } - implicit def canBuildFrom2: CanBuildFrom[String, Char, RichString] = - new CanBuildFrom[String, Char, RichString] { - def apply(from: String) = newBuilder - def apply() = newBuilder - } - - // just statics for rich string. - private final val LF: Char = 0x0A - private final val FF: Char = 0x0C - private final val CR: Char = 0x0D - private final val SU: Char = 0x1A -} - -import RichString._ - -class RichString(val self: String) extends Proxy with IndexedSeq[Char] with IndexedSeqLike[Char, RichString] with PartialFunction[Int, Char] with Ordered[String] with Boxed { - - /** Creates a string builder buffer as builder for this class */ - override protected[this] def newBuilder = RichString.newBuilder - - /** Return element at index `n` - * @throws IndexOutofBoundsException if the index is not valid - */ - def apply(n: Int): Char = self charAt n - - def length: Int = self.length - - override def mkString = self - override def toString = self - - /** return n times the current string - */ - def * (n: Int): String = { - val buf = new StringBuilder - 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 - - /**

- * Strip trailing line end character from this string if it has one. - * A line end character is one of - *

- * - *

- * If a line feed character LF is preceded by a carriage return CR - * (0x0D hex), the CR character is also stripped (Windows convention). - *

- */ - def stripLineEnd: String = { - val len = self.length - if (len == 0) self - else { - val last = apply(len - 1) - if (isLineBreak(last)) - self.substring(0, if (last == LF && len >= 2 && apply(len - 2) == CR) len - 2 else len - 1) - else - self - } - } - - /**

- * Return all lines in this string in an iterator, including trailing - * line end characters. - *

- *

- * The number of strings returned is one greater than the number of line - * end characters in this string. For an empty string, a single empty - * line is returned. A line end character is one of - *

- * - */ - def linesWithSeparators: Iterator[String] = new Iterator[String] { - private val len = self.length - private var index = 0 - def hasNext: Boolean = index < len - def next(): String = { - if (index >= len) throw new NoSuchElementException("next on empty iterator") - val start = index - while (index < len && !isLineBreak(apply(index))) index += 1 - index += 1 - self.substring(start, index min len) - } - } - - /** Return all lines in this string in an iterator, excluding trailing line - * end characters, i.e. apply .stripLineEnd to all lines - * returned by linesWithSeparators. - */ - def lines: Iterator[String] = - linesWithSeparators map (line => new RichString(line).stripLineEnd) - - /** Return all lines in this string in an iterator, excluding trailing line - * end characters, i.e. apply .stripLineEnd to all lines - * returned by linesWithSeparators. - */ - def linesIterator: Iterator[String] = - linesWithSeparators map (line => new RichString(line).stripLineEnd) - - /** Returns this string with first character converted to upper case */ - def capitalize: String = - if (self == null) null - else if (self.length == 0) "" - else { - val chars = self.toCharArray - chars(0) = chars(0).toUpper - new String(chars) - } - - /** Returns this string with the given prefix stripped. */ - def stripPrefix(prefix: String) = - if (self.startsWith(prefix)) self.substring(prefix.length) - else self - - /** Returns this string with the given suffix stripped. */ - def stripSuffix(suffix: String) = - if (self.endsWith(suffix)) self.substring(0, self.length() - suffix.length) - else self - - /**

- * For every line in this string: - *

- *
- * Strip a leading prefix consisting of blanks or control characters - * followed by marginChar from the line. - *
- */ - def stripMargin(marginChar: Char): String = { - val buf = new StringBuilder - for (line <- linesWithSeparators) { - val len = line.length - var index = 0 - while (index < len && line.charAt(index) <= ' ') index += 1 - buf append - (if (index < len && line.charAt(index) == marginChar) line.substring(index + 1) else line) - } - buf.toString - } - - /**

- * For every line in this string: - *

- *
- * Strip a leading prefix consisting of blanks or control characters - * followed by | from the line. - *
- */ - def stripMargin: String = stripMargin('|') - - private def escape(ch: Char): String = "\\Q" + ch + "\\E" - - @throws(classOf[java.util.regex.PatternSyntaxException]) - def split(separator: Char): Array[String] = self.split(escape(separator)) - - @throws(classOf[java.util.regex.PatternSyntaxException]) - def split(separators: Array[Char]): Array[String] = { - val re = separators.foldLeft("[")(_+escape(_)) + "]" - self.split(re) - } - - /** You can follow a string with `.r', turning - * it into a Regex. E.g. - * - * """A\w*""".r is the regular expression for identifiers starting with `A'. - */ - def r: Regex = new Regex(self) - - def toBoolean: Boolean = parseBoolean(self) - def toByte: Byte = java.lang.Byte.parseByte(self) - def toShort: Short = java.lang.Short.parseShort(self) - def toInt: Int = java.lang.Integer.parseInt(self) - def toLong: Long = java.lang.Long.parseLong(self) - def toFloat: Float = java.lang.Float.parseFloat(self) - def toDouble: Double = java.lang.Double.parseDouble(self) - - private def parseBoolean(s: String): Boolean = - if (s != null) s.toLowerCase match { - case "true" => true - case "false" => false - case _ => throw new NumberFormatException("For input string: \""+s+"\"") - } - else - throw new NumberFormatException("For input string: \"null\"") - - def toArray: Array[Char] = { - val result = new Array[Char](length) - self.getChars(0, length, result, 0) - result - } - - /**

- * Uses the underlying string as a pattern (in a fashion similar to - * printf in C), and uses the supplied arguments to fill in the - * holes. - *

- *

- * The interpretation of the formatting patterns is described in - * - * java.util.Formatter. - *

- * - * @param args the arguments used to instantiating the pattern. - * @throws java.lang.IllegalArgumentException - */ - def format(args : Any*) : String = - java.lang.String.format(self, args.asInstanceOf[Seq[AnyRef]]: _*) - - /**

- * Like format(args*) but takes an initial Locale parameter - * which influences formatting as in java.lang.String's format. - *

- *

- * The interpretation of the formatting patterns is described in - * - * java.util.Formatter. - *

- * - * @param locale an instance of java.util.Locale - * @param args the arguments used to instantiating the pattern. - * @throws java.lang.IllegalArgumentException - */ - def format(l: java.util.Locale, args: Any*): String = - java.lang.String.format(l, self, args.asInstanceOf[Seq[AnyRef]]: _*) -} - -- cgit v1.2.3