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

claimant.System.scala Maven / Gradle / Ivy

The newest version!
package claimant

import scala.reflect.macros.blackbox.Context

/**
 * System encapsulates the strategies used by Claimant.
 *
 * Tinkers describe how to decompose Boolean expressions, and scribes
 * describe how to label _any_ expression. Together we use them to
 * build labels for labeled Prop values.
 */
abstract class System { sys =>

  def tinkers: List[Tinker]
  def scribes: List[Scribe]
  def render(c: Context)(t: c.Tree): c.Tree

  final def tostr(c: Context)(t: c.Tree): c.Tree = {
    import c.universe._
    q"$t.toString"
  }

  /**
   * System.deconstruct is where the magic happens.
   *
   * This is the high-level logic of how Claimant works. Basically,
   * we're given a top-level Boolean expression. First we try to break
   * that expression into sub-expressions. Each Boolean sub-expression
   * which can't be split into smaller ones is represented by a simple
   * claim (Claim.Simple value). For each of these we generate a label.
   *
   * Then we recombine these claims using the same operations that
   * connected their sub-expressions (e.g. AND, OR, etc.), producing a
   * single top-level Claim.
   */
  def deconstruct(c: Context)(e0: c.Expr[Boolean]): c.Expr[Claim] = {
    import c.universe._
    def loop(lst: List[Tinker]): c.Expr[Claim] =
      lst match {
        case Nil =>
          val label = annotate(c)(e0.tree)
          c.Expr(q"_root_.claimant.Claim($e0, $label)")
        case tinker :: rest =>
          tinker.deconstruct(c)(e0, sys) match {
            case Some(e1) => e1
            case None => loop(rest)
          }
      }
    loop(tinkers)
  }

  /**
   * Annotate any Tree with a description of its expression.
   *
   * In many cases this will just stringify the resulting value of an
   * expression. But in other cases it will display parts of the
   * expression as well as its result.
   */
  def annotate(c: Context)(input: c.Tree): c.Tree = {
    def loop(lst: List[Scribe]): c.Tree =
      lst match {
        case Nil =>
          render(c)(input)
        case scribe :: rest =>
          scribe.annotate(c)(input, sys) match {
            case Some(t) => t
            case None => loop(rest)
          }
      }
    loop(scribes)
  }
}

object System {

  /**
   * Default system factory method.
   *
   * Builds using the given scribes and tinkers, using .toString to
   * stringify values.
   */
  def apply(tinkers0: List[Tinker], scribes0: List[Scribe]): System =
    new System {
      def tinkers: List[Tinker] = tinkers0
      def scribes: List[Scribe] = scribes0
      def render(c: Context)(t: c.Tree): c.Tree = {
        import c.universe._
        q"_root_.claimant.Render.render($t)"
      }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy