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

speed.impl.Generation.scala Maven / Gradle / Ivy

The newest version!
package speed.impl

trait Generation extends RangeGeneration with ListGeneration { self: SpeedImpl ⇒
  import c.universe._
  case class GeneratorSetup(inits: Seq[Tree], body: Tree) {
    def prependInits(inits: Seq[Tree]): GeneratorSetup = copy(inits = inits ++ this.inits)
  }
  object GeneratorSetup {
    implicit def treeToSetup(t: Tree): GeneratorSetup = GeneratorSetup(Nil, t)
  }
  case class TerminalOperationSetup(inits: Seq[Tree], inner: Tree, result: Tree)

  def generate(chain: OperationChain): Tree = {
    val cancelVar = c.fresh(newTermName("cancel$"))
    val varName = newTermName(c.fresh("value$"))

    val term = generateTerminal(chain.terminal, varName, cancelVar)
    //println(s"Term: $term")
    val GeneratorSetup(genInits, gen) = generateGen(chain.generator, varName, term.inner, cancelVar)
    //println(s"Gen: $gen")

    q"""
      var $cancelVar = false
      ..${genInits ++ term.inits}

      $gen

      ${term.result}
    """
  }

  def generateGen(gen: Generator, expectedValName: TermName, application: Tree, cancelVar: TermName): GeneratorSetup = gen match {
    case RangeGenerator(start, end, by, incl) ⇒ generateRange(start, end, by, incl, expectedValName, application, cancelVar)
    case ListGenerator(l, tpe)                ⇒ generateList(l, tpe, expectedValName, application, cancelVar)
    case MappingGenerator(outer, f) ⇒
      val tempName = c.fresh(newTermName("m$"))
      val body =
        q"""
            val $expectedValName = {
              val ${f.valName} = $tempName
              ${f.application}
            }
            $application
          """

      generateGen(outer, tempName, body, cancelVar)

    case FlatMappingGenerator(outer, innerValName, innerGenerator) ⇒
      val GeneratorSetup(inits, innerLoop) = generateGen(innerGenerator, expectedValName, application, cancelVar /* FIXME: is this correct? */ )
      generateGen(outer, innerValName, innerLoop, cancelVar).prependInits(inits)

    case FilteringGenerator(outer, f) ⇒
      val tempName = c.fresh(newTermName("m$"))
      val body =
        q"""
            if ({
              val ${f.valName} = $tempName
              ${f.application}
            }) {
              val $expectedValName = $tempName
              $application
            }
          """

      generateGen(outer, tempName, body, cancelVar)

    case InitAddingGenerator(outer, inits) ⇒ generateGen(outer, expectedValName, application, cancelVar).prependInits(inits)

    case TakeGenerator(outer, number) ⇒
      val counterVar = c.fresh(newTermName("counter$"))
      val init = q"var $counterVar = 0"
      val body = q"""
        if ($counterVar < $number) $application
        $counterVar += 1
      """

      // TODO: think about an early cancelling version
      // $cancelVar = $cancelVar || ($counterVar >= $number)

      generateGen(outer, expectedValName, body, cancelVar).prependInits(Seq(init))
  }
  def generateTerminal(terminal: TerminalOperation, valName: TermName, cancelVar: TermName): TerminalOperationSetup = terminal match {
    case Foreach(f) ⇒
      val body: Tree = q"""
      {
        val ${f.valName} = $valName
        ${f.application}
      }
      """

      TerminalOperationSetup(Seq(f.init), body, q"()")

    case FoldLeft(init, f) ⇒
      val accVar = c.fresh(newTermName("acc$"))
      val inits = Seq(q"var $accVar = ${init}", f.init)

      val body =
        q"""
          $accVar = {
            val ${f.valName1} = $accVar
            val ${f.valName2} = $valName
            ${f.application}
          }
        """

      TerminalOperationSetup(inits, body, q"$accVar")

    case Reduce(tpe, f) ⇒
      val accVar = c.fresh(newTermName("acc$"))
      val emptyVar = c.fresh(newTermName("empty$"))
      def b(b: Boolean) = Literal(Constant(b))
      val a1Type = tpe
      val neutralA1 = neutralElement(tpe)
      val inits = Seq(
        q"var $accVar: $a1Type = $neutralA1",
        q"var $emptyVar = ${b(true)}",
        f.init)
      val body =
        q"""
          if ($emptyVar) {
            $emptyVar = ${b(false)}
            $accVar = $valName
          } else
            $accVar = {
              val ${f.valName1} = $accVar
              val ${f.valName2} = $valName
              ${f.application}
            }
        """

      val result =
        q"""
              if ($emptyVar) throw new UnsupportedOperationException("Can't reduce empty range")
              else $accVar
            """

      TerminalOperationSetup(inits, body, result)

    case MkString ⇒
      val sbVar = c.fresh(newTermName("sb$"))
      val init = q"val $sbVar = new java.lang.StringBuilder"
      val body = q"$sbVar.append($valName.toString)"
      val result = q"$sbVar.toString"

      TerminalOperationSetup(Seq(init), body, result)

    case To(cbf) ⇒
      val builderVar = c.fresh(newTermName("builder$"))
      val init = q"val $builderVar = $cbf()"
      val body = q"$builderVar += $valName"
      val result = q"$builderVar.result()"

      TerminalOperationSetup(Seq(init), body, result)

    case Forall(f) ⇒
      val resultVar = c.fresh(newTermName("result$"))
      val init = q"var $resultVar = true"
      val body = q"""
        $resultVar = {
          val ${f.valName} = $valName
          ${f.application}
        }
        $cancelVar = $cancelVar || !$resultVar
      """
      val result = q"$resultVar"

      TerminalOperationSetup(Seq(init), body, result)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy