
scalariform.lexer.XmlLexer.scala Maven / Gradle / Ivy
The newest version!
package scalariform.lexer
import scala.annotation._
import scalariform.lexer.CharConstants.SU
import scalariform.lexer.ScalaLexer._
import scalariform.lexer.Tokens._
import scalariform.utils.Utils
import scala.PartialFunction.cond
/**
* Lexer implementation for XML literals and patterns
*/
trait XmlLexer { self: ScalaLexer ⇒
private def tagMode = xmlMode.isTagMode
private def tagMode_=(isTagMode: Boolean) {
xmlMode.isTagMode = isTagMode
}
private def moreXmlToCome: Boolean = {
// Amount of scanning ahead required is unlimited, so we can't use the circular buffer:
val newReader = reader.copy.buffered
while (newReader.head != SU && isSpace(newReader.head))
newReader.next()
cond(newReader.take(2).toList) {
case List(c1, c2) ⇒ c1 == '<' && isNameStart(c2)
}
}
protected def fetchXmlToken() {
(ch: @switch) match {
case '<' ⇒ {
if (ch(1) == '/') {
nextChar()
nextChar()
token(XML_END_OPEN)
xmlMode.isTagMode = true
xmlMode.tagState = InEndTag
} else if (ch(1) == '!') {
if (ch(2) == '-') {
getXmlComment()
if (xmlMode.nestingLevel == 0 && !moreXmlToCome)
popMode()
} else if (ch(2) == '[') {
getXmlCDATA()
if (xmlMode.nestingLevel == 0 && !moreXmlToCome)
popMode()
} else {
if (forgiveErrors) {
munch("') {
nextChar()
nextChar()
token(XML_EMPTY_CLOSE)
xmlMode.isTagMode = false
xmlMode.tagState = Normal
if (xmlMode.nestingLevel == 0 && !moreXmlToCome)
popMode()
} else
getXmlCharData()
} else
getXmlCharData()
}
case '>' ⇒
if (tagMode) {
nextChar()
token(XML_TAG_CLOSE)
xmlMode.isTagMode = false
xmlMode.tagState match {
case InStartTag ⇒ xmlMode.nestTag()
case InEndTag ⇒ {
val nestingLevel = xmlMode.unnestTag()
if (nestingLevel == 0 && !moreXmlToCome)
popMode()
}
case Normal ⇒ throw new AssertionError("shouldn't reach here")
}
} else
getXmlCharData()
case '=' ⇒
if (tagMode) {
nextChar()
token(XML_ATTR_EQ)
} else {
getXmlCharData()
}
case '\'' ⇒
if (tagMode) {
getXmlAttributeValue('\'')
} else {
getXmlCharData()
}
case '"' ⇒
if (tagMode) {
getXmlAttributeValue('"')
} else {
getXmlCharData()
}
case '{' ⇒
if (ch(1) != '{')
switchToScalaModeAndFetchToken
else
getXmlCharData() // TODO: tagMode?
case SU ⇒ token(EOF)
case _ ⇒
if (tagMode && isNameStart(ch)) {
getXmlName()
} else if (tagMode && isSpace(ch)) {
getXmlSpace()
} else {
getXmlCharData()
// throw new ScalaLexerException("illegal character in xml: " + Character.valueOf(ch))
// TODO
}
}
}
private def getXmlCDATA() {
munch("")) {
munch("]]>")
continue = false
} else if (ch == SU)
if (forgiveErrors)
continue = false
else
throw new ScalaLexerException("Malformed XML CDATA")
else
nextChar()
}
token(XML_CDATA)
}
private def getXmlComment() {
munch("