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

basis.form.JsonStringContext.scala Maven / Gradle / Ivy

//      ____              ___
//     / __ | ___  ____  /__/___      A library of building blocks
//    / __  / __ |/ ___|/  / ___|
//   / /_/ / /_/ /\__ \/  /\__ \      (c) 2012-2015 Chris Sachs
//  |_____/\_____\____/__/\____/      http://basis.reify.it

package basis.form

import scala.reflect.macros._

class JsonStringContext[-V <: JsonVariant](variant: V, stringContext: StringContext) {
  def json(args: V#AnyForm*): V#AnyForm        = macro JsonStringContextMacros.json[V]
  def jsobject(args: V#AnyForm*): V#ObjectForm = macro JsonStringContextMacros.jsobject[V]
  def jsarray(args: V#AnyForm*): V#SeqForm     = macro JsonStringContextMacros.jsarray[V]
}

private[form] class JsonVariantMacros(val c: blackbox.Context { type PrefixType <: JsonVariant }) {
  import c.{ Expr, mirror, prefix, WeakTypeTag }
  import c.universe._

  def JsonStringContext[V <: JsonVariant](stringContext: Expr[StringContext]): Expr[JsonStringContext[V]] = {
    implicit val JsonStringContextV = JsonStringContextTag[V]
    Expr[JsonStringContext[V]](q"new $JsonStringContextV($prefix, $stringContext)")
  }

  implicit private def JsonStringContextTag[V <: JsonVariant]: WeakTypeTag[JsonStringContext[V]] =
    WeakTypeTag[JsonStringContext[V]](
      appliedType(
        mirror.staticClass("basis.form.JsonStringContext").toTypeConstructor,
        (if (prefix.actualType != null) prefix.actualType else prefix.staticType) :: Nil))
}

private[form] class JsonStringContextMacros(val c: blackbox.Context { type PrefixType <: JsonStringContext[_] }) {
  import c.{ abort, Expr, prefix }
  import c.universe._

  @inline private def interpolate[V <: JsonVariant : WeakTypeTag, T](args: Seq[Expr[V#AnyForm]])(parse: (JsonInterpolator, JsonExprFactory[c.type, V]) => Expr[T]): Expr[T] = {
    val Typed(Apply(_, variant :: stringContext :: Nil), _) = prefix.tree
    val Apply(_, stringLiterals) = stringContext
    val strings = scala.collection.mutable.ListBuffer.empty[String]
    val literals = stringLiterals.iterator
    while (literals.hasNext) {
      val Literal(Constant(string: String)) = literals.next()
      strings += string
    }

    val factory = new JsonExprFactory[c.type, V](c)(Expr[V](variant))
    val parser = new JsonInterpolator(strings, args.iterator)

    try {
      parser.skipWhitespace()
      val expr = parse(parser, factory)
      parser.skipWhitespace()
      parser.parseEOF()
      expr
    }
    catch {
      case e: JsonException =>
        val partPos = stringLiterals(e.part).pos
        val errorPos = partPos.withPoint(partPos.point + e.offset)
        abort(errorPos, e.getMessage)
    }
  }

  def json[V <: JsonVariant : WeakTypeTag](args: Expr[V#AnyForm]*): Expr[V#AnyForm] =
    interpolate[V, V#AnyForm](args)((parser, factory) => parser.parseValue(factory))

  def jsobject[V <: JsonVariant : WeakTypeTag](args: Expr[V#AnyForm]*): Expr[V#ObjectForm] =
    interpolate[V, V#ObjectForm](args)((parser, factory) => parser.parseObject(factory)(factory.JsonObjectBuilder))

  def jsarray[V <: JsonVariant : WeakTypeTag](args: Expr[V#AnyForm]*): Expr[V#SeqForm] =
    interpolate[V, V#SeqForm](args)((parser, factory) => parser.parseArray(factory)(factory.JsonArrayBuilder))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy