summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala54
-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
4 files changed, 69 insertions, 65 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
index bd46d2219d..1f17f148aa 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
@@ -36,6 +36,9 @@ trait MarkupParsers
{
self: Parsers =>
+ type PositionType = Position
+ type InputType = CharArrayReader
+
case object MissingEndTagException extends RuntimeException with ControlException {
override def getMessage = "start tag was here: "
}
@@ -62,6 +65,8 @@ trait MarkupParsers
else reportSyntaxError(msg)
var input : CharArrayReader = _
+ def lookahead(): BufferedIterator[Char] =
+ (input.buf drop input.charOffset).iterator.buffered
import parser.{ symbXMLBuilder => handle, o2p, r2p }
@@ -83,7 +88,6 @@ trait MarkupParsers
private var debugLastStartElement = new mutable.Stack[(Int, String)]
private def debugLastPos = debugLastStartElement.top._1
private def debugLastElem = debugLastStartElement.top._2
- private def unreachable = Predef.error("Cannot be reached.")
private def errorBraces() = {
reportSyntaxError("in XML content, please use '}}' to express '}'")
@@ -190,55 +194,13 @@ trait MarkupParsers
xToken('>')
}
- /** 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 = {
- val la = input.lookaheadReader
- for (c <- lookingFor) {
- la.nextChar()
- if (la.ch != c)
- return false
- }
- // drop the chars from the real reader (all lookahead + orig)
- (0 to lookingFor.length) foreach (_ => nextch)
- true
- }
-
- /** 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.
- */
- private def xTakeUntil[T](
- handler: (Position, String) => T,
- positioner: () => Position,
- 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)
- throw TruncatedXML
-
- sb append ch
- nextch
- }
- unreachable
- }
-
/** '<! CharData ::= [CDATA[ ( {char} - {char}"]]>"{char} ) ']]>'
*
* see [15]
*/
def xCharData: Tree = {
val start = curOffset
- "[CDATA[" foreach xToken
+ xToken("[CDATA[")
val mid = curOffset
xTakeUntil(handle.charData, () => r2p(start, mid, curOffset), "]]>")
}
@@ -284,7 +246,7 @@ trait MarkupParsers
*/
def xComment: Tree = {
val start = curOffset - 2 // Rewinding to include "<!"
- "--" foreach xToken
+ xToken("--")
xTakeUntil(handle.comment, () => r2p(start, start, curOffset), "-->")
}
@@ -374,7 +336,7 @@ trait MarkupParsers
val start = curOffset
val (qname, attrMap) = xTag
if (ch == '/') { // empty element
- "/>" foreach xToken
+ xToken("/>")
handle.element(r2p(start, start, curOffset), qname, attrMap, new ListBuffer[Tree])
}
else { // handle content
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
+ }
}