summaryrefslogtreecommitdiff
path: root/src/library
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-01-15 02:12:10 +0000
committerPaul Phillips <paulp@improving.org>2010-01-15 02:12:10 +0000
commit2d324f4506191ba9059e14fa7482c2276b5f255a (patch)
treede9b4d00d4864eaaffdd033d36edf420ba83f619 /src/library
parentdf4d259938d2a522ba0726e86ded78d2a09982ce (diff)
downloadscala-2d324f4506191ba9059e14fa7482c2276b5f255a.tar.gz
scala-2d324f4506191ba9059e14fa7482c2276b5f255a.tar.bz2
scala-2d324f4506191ba9059e14fa7482c2276b5f255a.zip
Fix and test for #2354. Review by community.
Diffstat (limited to 'src/library')
-rw-r--r--src/library/scala/collection/Iterator.scala5
-rw-r--r--src/library/scala/xml/parsing/MarkupParser.scala27
-rw-r--r--src/library/scala/xml/parsing/MarkupParserCommon.scala48
3 files changed, 61 insertions, 19 deletions
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index 5f28161ed3..6be99bf27c 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -1112,9 +1112,10 @@ trait Iterator[+A] { self =>
res.toList
}
- /** Traverses this iterator and returns all produced values in a list.
+ /** Lazily wraps a Stream around this iterator so its values are memoized.
*
- * @return a stream which contains all values produced by this iterator.
+ * @return a Stream which can repeatedly produce all the values
+ * produced by this iterator.
*/
def toStream: Stream[A] =
if (hasNext) Stream.cons(next, toStream) else Stream.empty
diff --git a/src/library/scala/xml/parsing/MarkupParser.scala b/src/library/scala/xml/parsing/MarkupParser.scala
index 2779fe1d7c..a15cd0f7e4 100644
--- a/src/library/scala/xml/parsing/MarkupParser.scala
+++ b/src/library/scala/xml/parsing/MarkupParser.scala
@@ -32,6 +32,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
self: MarkupParser with MarkupHandler =>
type PositionType = Int
+ type InputType = Source
def xHandleError(that: Char, msg: String) = reportSyntaxError(msg)
@@ -47,6 +48,15 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
//
var curInput: Source = input
+ def lookahead(): BufferedIterator[Char] = new BufferedIterator[Char] {
+ val stream = curInput.toStream
+ curInput = Source.fromIterable(stream)
+ val underlying = Source.fromIterable(stream).buffered
+
+ def hasNext = underlying.hasNext
+ def next = underlying.next
+ def head = underlying.head
+ }
/** the handler of the markup, returns this */
private val handle: MarkupHandler = this
@@ -57,7 +67,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
/** holds the position in the source file */
var pos: Int = _
-
/* used when reading external subset */
var extIndex = -1
@@ -379,20 +388,8 @@ trait MarkupParser extends MarkupParserCommon with TokenTests
*/
def xCharData: NodeSeq = {
xToken("[CDATA[")
- val pos1 = pos
- val sb: StringBuilder = new StringBuilder()
- while (true) {
- if (ch==']' &&
- { sb.append(ch); nextch; ch == ']' } &&
- { sb.append(ch); nextch; ch == '>' } ) {
- sb.setLength(sb.length - 2);
- nextch;
- return PCData(sb.toString)
- } else sb.append( ch );
- nextch;
- }
- // bq: (todo) increase grace when meeting CDATA section
- throw FatalError("this cannot happen");
+ def mkResult(pos: Int, s: String): NodeSeq = PCData(s)
+ xTakeUntil(mkResult, () => pos, "]]>")
}
/** CharRef ::= "&amp;#" '0'..'9' {'0'..'9'} ";"
diff --git a/src/library/scala/xml/parsing/MarkupParserCommon.scala b/src/library/scala/xml/parsing/MarkupParserCommon.scala
index c4ba2ccf15..57c46c4685 100644
--- a/src/library/scala/xml/parsing/MarkupParserCommon.scala
+++ b/src/library/scala/xml/parsing/MarkupParserCommon.scala
@@ -18,9 +18,16 @@ import Utility.Escapes.{ pairs => unescape }
* All members should be accessed through those.
*/
private[scala] trait MarkupParserCommon extends TokenTests {
- // type InputType // Source, CharArrayReader
+ private final val SU: Char = 0x1A
+ protected def unreachable = Predef.error("Cannot be reached.")
+
// type HandleType // MarkupHandler, SymbolicXMLBuilder
- // type PositionType // Int, Position
+
+ type InputType // Source, CharArrayReader
+ type PositionType // Int, Position
+
+ /** Create a lookahead reader which does not influence the input */
+ def lookahead(): BufferedIterator[Char]
def ch: Char
def nextch: Char
@@ -48,4 +55,41 @@ private[scala] trait MarkupParserCommon extends TokenTests {
//
def returning[T](x: T)(f: T => Unit): T = { f(x) ; x }
+
+ /** Take characters from input stream until given String "until"
+ * is seen. Once seen, the accumulated characters are passed
+ * along with the current Position to the supplied handler function.
+ */
+ protected def xTakeUntil[T](
+ handler: (PositionType, String) => T,
+ positioner: () => PositionType,
+ until: String): T =
+ {
+ val sb = new StringBuilder
+ val head = until charAt 0
+ val rest = until drop 1
+
+ while (true) {
+ if (ch == head && peek(rest))
+ return handler(positioner(), sb.toString)
+ else if (ch == SU)
+ xHandleError(ch, "") // throws TruncatedXML in compiler
+
+ sb append ch
+ nextch
+ }
+ unreachable
+ }
+
+ /** Create a non-destructive lookahead reader and see if the head
+ * of the input would match the given String. If yes, return true
+ * and drop the entire String from input; if no, return false
+ * and leave input unchanged.
+ */
+ private def peek(lookingFor: String): Boolean =
+ (lookahead() take lookingFor.length sameElements lookingFor.iterator) && {
+ // drop the chars from the real reader (all lookahead + orig)
+ (0 to lookingFor.length) foreach (_ => nextch)
+ true
+ }
}