All Downloads are FREE. Search and download functionalities are using the official Maven repository.

wjson.JsonInterpolation.scala Maven / Gradle / Ivy

package wjson

import wjson.JsValue.JsNull

/**
 * Created by wangzx on 15/7/6.
 */

class JsonInterpolation(sc: StringContext) {

  object Placeholder {
    def apply(index: Int): JsValue = JsString("\u0000_placeholder_" + index + "_\u0000")
    def unapply(str: JsValue): Option[Int] = {
      str match
        case JsString(str) if str.startsWith("\u0000_placeholder_") && str.endsWith("_\u0000") =>
          Some(str.substring(14, str.length - 2).nn.toInt)
        case _ => None
    }
  }

  protected def parse(input: ParserInput): JsValue =
    new JsonParser(input).parseJsValue()

  def apply(args: JsValue*): JsValue =
    parse( ParserInput(sc, args) )

  def unapplySeq(input: JsValue): Option[Seq[JsValue]] = {

    val placeHolders: Seq[JsValue] = Seq.range(0, sc.parts.length-1)
      .map(x => Placeholder(x) )

    val pi = ParserInput(sc, placeHolders)
    val pattern = parse( pi )

    val results = collection.mutable.ArrayBuffer[JsValue]()
    Seq.range(0, sc.parts.length-1).foreach { _ => results += JsNull }

    try {
      patternMatch(pattern, input, placeHolders, results)
      Some(results.toSeq)
    }
    catch {
      case _: Throwable => None
    }

  }

  // TODO report friendly
  private def patternMatch(pattern: JsValue, input: JsValue, placeHolders: Seq[JsValue],
                           results: collection.mutable.ArrayBuffer[JsValue]): Unit = {

    pattern match {
      case p_o: JsObject =>
        assert( input.isInstanceOf[JsObject] )
        val inputObj = input.asObj

        p_o.fields.foreach {
          case (key, Placeholder(index))  =>
            assert( inputObj.contains(key) )
            results(index) = inputObj.field(key)

          case (key, value) =>
            assert(inputObj.contains(key))
            patternMatch(value, inputObj.field(key), placeHolders, results)
        }

      case p_a: JsArray =>
        assert(input.isInstanceOf[JsArray] &&
               input.asArr.elements.size >= p_a.elements.size)
        val inputArr = input.asArr

        p_a.elements.zipWithIndex.foreach {
          case (Placeholder(index), y: Int) =>
            results(index) = inputArr.elements(y)
          case (x: JsValue,y: Int)=>
            patternMatch(x, inputArr.elements.apply(y), placeHolders, results)
        }

      case p: JsString =>
        assert(p == input)
      case p: JsBoolean =>
        assert(p == input)
      case p: JsNumber =>
        assert(p == input)
      case p@ JsNull =>
        assert(p == input)
    }
  }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy