hayio
6/17/2015 - 10:07 PM

Example of parser combinator.

Example of parser combinator.

object Tmp {
  def main(args: Array[String]) = {
    val parser = new JsPageDataParser

    parser.parse(
      """
        |var matchCentreData = {"a":{"xx":"fsdf","aa":{"aaa":"bbb","ccc":"ddd"}}}
      """.stripMargin.trim)
  }
}

/**
 * Created on 16.06.15.
 */
class JsPageDataParser {

  val parser = new JsParser

  def parse(content: String) = {
    val result = parser.parseAll(parser.matchCentreData, content).get

    println("DONE:")
    println(result)
  }
}

class JsParser extends RegexParsers {

  val strLiteral = "[^:\"]+".r

  def matchCentreData: Parser[Seq[NestedMap]] = "var matchCentreData = " ~> jsDict

  def jsDict: Parser[Seq[NestedMap]] = "{" ~> repsep(keyValue, ",") <~ "}"

  def keyValue: Parser[NestedMap] = (("\"" ~ strLiteral ~ "\":" ~ mapValue) ^^ {
    case "\"" ~ mapKey ~ "\":" ~ mapVal =>
      NestedMap(Map(mapKey -> mapVal))
  })

  def mapValue: Parser[Either[String, NestedMap]] = (jsDict | quoted) ^^ {
    case str: String => Left(str)
    case dict: Seq[NestedMap] => Right(dict.foldLeft(NestedMap(Map.empty)) {
      case (agg, map) => NestedMap(agg.kvs + (map.kvs.head))
    })
  }

  // x~>y<~z despite arrow directions alway has order of matching from left to right
  // so be careful not to eat in y every char
  def quoted: Parser[String] = "\"" ~> strLiteral <~ "\""
}

case class NestedMap(kvs: Map[String, Either[String, NestedMap]])