implemented parser for escaped string and verbatim string

This commit is contained in:
e.e d3si9n 2012-03-11 07:31:39 -04:00
parent c6f28c650d
commit 87c52f5f1b
1 changed files with 44 additions and 1 deletions

View File

@ -17,6 +17,10 @@ trait Parsers
lazy val DigitSet = Set("0","1","2","3","4","5","6","7","8","9")
lazy val Digit = charClass(_.isDigit, "digit") examples DigitSet
lazy val OctalDigitSet = Set("0","1","2","3","4","5","6","7")
lazy val OctalDigit = charClass(c => OctalDigitSet(c.toString), "octal") examples OctalDigitSet
lazy val HexDigitSet = Set("0","1","2","3","4","5","6","7","8","9", "A", "B", "C", "D", "E", "F")
lazy val HexDigit = charClass(c => HexDigitSet(c.toString.toUpperCase), "hex") examples HexDigitSet
lazy val Letter = charClass(_.isLetter, "letter")
def IDStart = Letter
lazy val IDChar = charClass(isIDChar, "ID character")
@ -44,6 +48,12 @@ trait Parsers
lazy val Space = SpaceClass.+.examples(" ")
lazy val OptSpace = SpaceClass.*.examples(" ")
lazy val URIClass = URIChar.+.string !!! "Invalid URI"
lazy val VerbatimDQuotes = "\"\"\""
lazy val DQuoteChar = '\"'
lazy val DQuoteClass = charClass(_ == DQuoteChar, "double-quote character")
lazy val NotDQuoteClass = charClass(_ != DQuoteChar, "non-double-quote character")
lazy val NotDQuoteBackslashClass = charClass({ c: Char =>
c != DQuoteChar && c != '\\' }, "non-double-quote character")
lazy val URIChar = charClass(alphanum) | chars("_-!.~'()*,;:$&+=?/[]@%#")
def alphanum(c: Char) = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')
@ -57,6 +67,39 @@ trait Parsers
private[this] def toInt(neg: Option[Char], digits: Seq[Char]): Int =
(neg.toSeq ++ digits).mkString.toInt
lazy val Bool = ("true" ^^^ true) | ("false" ^^^ false)
lazy val StringBasic = StringVerbatim | StringEscapable | NotQuoted
def StringVerbatim: Parser[String] = {
var dqcount = 0
val p = VerbatimDQuotes ~
charClass(_ match {
case DQuoteChar =>
dqcount += 1
dqcount < 3
case _ =>
dqcount = 0
true
}).*.string ~ DQuoteChar
p map { case ((s, p), c) => s + p + c.toString } filter(
{ _.endsWith(VerbatimDQuotes) }, _ => "Expected '%s'" format VerbatimDQuotes) map { s =>
s.substring(3, s.length - 3) }
}
lazy val StringEscapable: Parser[String] = {
val p = DQuoteChar ~>
(EscapeSequence | NotDQuoteBackslashClass map {_.toString}).* <~ DQuoteChar
p map { _.mkString }
}
lazy val EscapeSequence: Parser[String] =
"\\" ~> ("b" ^^^ "\b" | "t" ^^^ "\t" | "n" ^^^ "\n" | "f" ^^^ "\f" | "r" ^^^ "\r" |
"\"" ^^^ "\"" | "'" ^^^ "\'" | "\\" ^^^ "\\" | OctalEscape | UnicodeEscape)
lazy val OctalEscape: Parser[String] =
repeat(OctalDigit, 1, 3) map { seq =>
Integer.parseInt(seq.mkString, 8).asInstanceOf[Char].toString
}
lazy val UnicodeEscape: Parser[String] =
("u" ~> repeat(HexDigit, 4, 4)) map { seq =>
Integer.parseInt(seq.mkString, 16).asInstanceOf[Char].toString
}
lazy val NotQuoted = (NotDQuoteClass ~ NotSpace) map { case (c, s) => c.toString + s }
def repsep[T](rep: Parser[T], sep: Parser[_]): Parser[Seq[T]] =
rep1sep(rep, sep) ?? Nil
@ -67,7 +110,7 @@ trait Parsers
def mapOrFail[S,T](p: Parser[S])(f: S => T): Parser[T] =
p flatMap { s => try { success(f(s)) } catch { case e: Exception => failure(e.toString) } }
def spaceDelimited(display: String): Parser[Seq[String]] = (token(Space) ~> token(NotSpace, display)).* <~ SpaceClass.*
def spaceDelimited(display: String): Parser[Seq[String]] = (token(Space) ~> token(StringBasic, display)).* <~ SpaceClass.*
def flag[T](p: Parser[T]): Parser[Boolean] = (p ^^^ true) ?? false