diff options
author | Burak Emir <emir@epfl.ch> | 2007-07-07 14:59:10 +0000 |
---|---|---|
committer | Burak Emir <emir@epfl.ch> | 2007-07-07 14:59:10 +0000 |
commit | 40430c44da16f8f9231dbfc481f7e316509b081c (patch) | |
tree | f60f79561c69e5bfe6918137d14a733e7d9226f1 | |
parent | c08f1700cad2b48114a39608c70906b18c192106 (diff) | |
download | scala-40430c44da16f8f9231dbfc481f7e316509b081c.tar.gz scala-40430c44da16f8f9231dbfc481f7e316509b081c.tar.bz2 scala-40430c44da16f8f9231dbfc481f7e316509b081c.zip |
JSON parsing by Derek Chen-Becker
-rw-r--r-- | src/library/scala/util/parsing/json/JSON.scala | 40 | ||||
-rw-r--r-- | src/library/scala/util/parsing/json/Lexer.scala | 75 | ||||
-rw-r--r-- | src/library/scala/util/parsing/json/Parser.scala | 31 |
3 files changed, 146 insertions, 0 deletions
diff --git a/src/library/scala/util/parsing/json/JSON.scala b/src/library/scala/util/parsing/json/JSON.scala new file mode 100644 index 0000000000..e0431f5724 --- /dev/null +++ b/src/library/scala/util/parsing/json/JSON.scala @@ -0,0 +1,40 @@ +package scala.util.parsing.json + +import scala.collection.mutable.HashMap + +/** This object mainly shows how a JSON parser maybe instantiated + * + */ +object JSON extends Parser { + def parse(input: String) = + phrase(root)(new lexical.Scanner(input)) match { + case Success(result, _) => Some(result) + case _ => None + } + + def parseFull(input: String) = parse(input) match { + case Some(data) => resolveType(data) + case None => None + } + + def resolveType(input: Any): Any = + input match { + case jo: List[(String,Any)] => + /*println("Resolving object")*/ + val objMap = new HashMap[String,Any]() + + jo.foreach { + case (key,value) => + objMap.update(key,resolveType(value)) + } + + objMap + + case ja: List[Any] => + /*println("Resolving array"); */ + ja.toArray + case _ @ elem => + /*println("Resolving element"); */ + elem + } +} diff --git a/src/library/scala/util/parsing/json/Lexer.scala b/src/library/scala/util/parsing/json/Lexer.scala new file mode 100644 index 0000000000..6a6b3684a2 --- /dev/null +++ b/src/library/scala/util/parsing/json/Lexer.scala @@ -0,0 +1,75 @@ +package scala.util.parsing.json + +import scala.util.parsing.combinator._ +import scala.util.parsing.combinator.syntactical._ +import scala.util.parsing.combinator.lexical._ +import scala.util.parsing.input.CharArrayReader.EofCh +import scala.util.parsing.combinator.~ + +/** + * @author Derek Chen-Becker <java@chen-becker.org> + */ + +class Lexer extends StdLexical with ImplicitConversions { + + override def token: Parser[Token] = + ('\"' ~ rep(charSeq | letter) ~ '\"' ^^ lift(StringLit) + | number ~ letter ^^ { case n ~ l => ErrorToken("Invalid number format : " + n + l) } + | '-' ~ whitespace ~ number ~ letter ^^ {case ws ~ num ~ l => ErrorToken("Invalid number format : -" + num + l) } + | '-' ~ whitespace ~ number ^^ {case ws ~ num => NumericLit("-" + num)} + | number ^^ NumericLit + | EofCh ^^ EOF + | delim + | '\"' ~ failure("Unterminated string") + | rep(letter) ^^ checkKeyword + | failure("Illegal character") + ) + + def checkKeyword(xs : List[Any]) = { + val strRep = xs.mkString("") + if (reserved.contains(strRep)) Keyword(strRep) else ErrorToken("Not a keyword: " + strRep) + } + + override def whitespace = rep(whitespaceChar) + + def number = intPart ~ opt(fracPart) ~ opt(expPart) ^^ { case i ~ f ~ e => + i + optString(".",f) + optString("",e) + } + def intPart = zero | intList + def intList = nonzero ~ rep(digit) ^^ {case x ~ y => (x :: y) mkString ""} + def fracPart = '.' ~ rep(digit) ^^ {x => x.mkString("")} + def expPart = exponent ~ opt(sign) ~ rep1(digit) ^^ { case e ~ s ~ d => + e + optString("",s) + d.mkString("") + } + + def optString[A](pre: String, a: Option[A]) = a match { + case Some(x) => pre + x.toString + case None => "" + } + + def zero: Parser[String] = '0' ^^ toString + def nonzero = elem("nonzero digit", d => d.isDigit && d != '0') + def exponent = elem("exponent character", d => d == 'e' || d == 'E') + def sign = elem("sign character", d => d == '-' || d == '+') + + def charSeq: Parser[String] = + ('\\' ~ '\"' ^^ "\"" + |'\\' ~ '\\' ^^ "\\" + |'\\' ~ '/' ^^ "/" + |'\\' ~ 'b' ^^ "\b" + |'\\' ~ 'f' ^^ "\f" + |'\\' ~ 'n' ^^ "\n" + |'\\' ~ 'r' ^^ "\r" + |'\\' ~ 't' ^^ "\t" + |'\\' ~ 'u' ~ unicodeBlock) + + val hexDigits = Set[Char]() ++ "0123456789abcdefABCDEF".toArray + def hexDigit = elem("hex digit", hexDigits.contains(_)) + + def unicodeBlock = hexDigit ~ hexDigit ~ hexDigit ~ hexDigit ^^ { + case a ~ b ~ c ~ d => + new String(Character.toChars(Integer.parseInt(List(a,b,c,d).mkString(""),16))) + } + + private def lift[T](f: String => T)(xs: List[Any]): T = f(xs.mkString("")) +} diff --git a/src/library/scala/util/parsing/json/Parser.scala b/src/library/scala/util/parsing/json/Parser.scala new file mode 100644 index 0000000000..8c94e060eb --- /dev/null +++ b/src/library/scala/util/parsing/json/Parser.scala @@ -0,0 +1,31 @@ +package scala.util.parsing.json; + +import scala.util.parsing.combinator._ +import scala.util.parsing.combinator.syntactical._ +import scala.util.parsing.combinator.lexical._ +import scala.util.parsing.input.CharArrayReader.EofCh +import scala.util.parsing.combinator.~ + +/** + * @author Derek Chen-Becker <java@chen-becker.org> + */ + +class Parser extends StdTokenParsers with ImplicitConversions { + // Fill in abstract defs + type Tokens = Lexer + val lexical = new Tokens + + // Configure lexical parsing + lexical.reserved ++= List("true", "false", "null") + lexical.delimiters ++= List("{", "}", "[", "]", ":", ",") + + // Define the grammar + def root = jsonObj | jsonArray + def jsonObj = "{" ~ repsep(objEntry,",") ~ "}" + def jsonArray = "[" ~ repsep(value, ",") ~ "]" + def objEntry = stringVal ~ ":" ~ value ^^ { case x ~ y => (x,y) } + def value: Parser[Any] = (jsonObj | jsonArray | number | "true" ^^ true | "false" ^^ false | "null" ^^ null | stringVal) + def stringVal = accept("string", {case lexical.StringLit(n) => n}) + def number = accept("number", {case lexical.NumericLit(n) => n.toDouble}) +} + |