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

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

The newest version!
package speed.impl

trait Analyzer { self: SpeedImpl ⇒
  import c.universe._

  def analyze(t: Tree): OperationChain = t match {
    case q"$inner.foreach[..${ _ }]($f)"         ⇒ OperationChain(analyzeGen(inner), Foreach(closure1(f)))
    case q"$inner.foldLeft[..${ _ }]($init)($f)" ⇒ OperationChain(analyzeGen(inner), FoldLeft(init, closure2(f)))
    case q"$inner.reduce[$t]($f)"                ⇒ OperationChain(analyzeGen(inner), Reduce(t.tpe, closure2(f)))
    case q"$inner.sum[..${ _ }]($num)"           ⇒ OperationChain(analyzeGen(inner), Sum(num))
    case q"$inner.min[..${ _ }]($ord)"           ⇒ OperationChain(analyzeGen(inner), Min(ord))
    case q"$inner.max[..${ _ }]($ord)"           ⇒ OperationChain(analyzeGen(inner), Max(ord))
    case q"$inner.size"                          ⇒ OperationChain(analyzeGen(inner), Size)
    case q"$inner.count($f)"                     ⇒ OperationChain(analyzeGen(inner), Count(closure1(f)))
    case q"$inner.mkString"                      ⇒ OperationChain(analyzeGen(inner), MkString)
    case q"$inner.to[..${ _ }]($cbf)"            ⇒ OperationChain(analyzeGen(inner), To(cbf))
    case q"$inner.forall($f)"                    ⇒ OperationChain(analyzeGen(inner), Forall(closure1(f)))
  }
  val arrayOps = Set("boolean", "byte", "char", "double", "float", "int", "long", "ref", "short", "unit").map(_ + "ArrayOps")
  def analyzeGen(t: Tree): Generator = t match {
    case q"$inner.map[..${ _ }]($f)"        ⇒ MappingGenerator(analyzeGen(inner), closure1(f))
    case q"$inner.filter[..${ _ }]($f)"     ⇒ FilteringGenerator(analyzeGen(inner), closure1(f))
    case q"$inner.withFilter[..${ _ }]($f)" ⇒ FilteringGenerator(analyzeGen(inner), closure1(f))
    case q"$inner.reverse"                  ⇒ ReverseGenerator(analyzeGen(inner))
    case q"$inner.take($els)"               ⇒ TakeGenerator(analyzeGen(inner), els)
    case q"$inner.flatMap[..${ _ }]($f)" ⇒
      val cl = closure1(f)
      val innerGenTree = cl.application match {
        case q"$innerGeneratorTree: @speed.dontfold" ⇒ innerGeneratorTree
      }

      FlatMappingGenerator(analyzeGen(inner), cl.valName, analyzeGen(innerGenTree))

    case q"${ _ }.RangesAreSpeedy($r).speedy" ⇒ range(r)
    case q"${ _ }.IndexedSeqsAreSpeedy[..${ _ }]($s).speedy" ⇒ IndexedGenerator(q"$s: @speed.dontfold")
    case q"${ _ }.ArraysAreSpeedy[..${ _ }]($a).speedy" ⇒ IndexedGenerator(q"$a: @speed.dontfold")
    case q"${ _ }.ListsAreSpeedy[..${ _ }]($l).speedy" ⇒ ListGenerator(q"$l: @speed.dontfold", l.tpe.widen)

    case q"${ _ }.auto.$name[..${ _ }]($a)" if arrayOps(name.decoded) ⇒ IndexedGenerator(q"$a: @speed.dontfold")
    case q"${ _ }.auto.intWrapper($i).$m(..${ _ }).by(..${ _ })" ⇒ range(t)
    case q"${ _ }.auto.intWrapper($i).$m(..${ _ })" ⇒ range(t)

    case _ ⇒ error(s"Unknown Prefix: $t")
  }
  def range(t: Tree): Generator = t match {
    case q"${ _ }.intWrapper($from).to($to)"               ⇒ RangeGenerator(from, to, c.literal(1).tree, q"true")
    case q"${ _ }.intWrapper($from).to($to).by($by)"       ⇒ RangeGenerator(from, to, by, q"true")
    case q"${ _ }.intWrapper($from).until($until)"         ⇒ RangeGenerator(from, until, c.literal(1).tree, q"false")
    case q"${ _ }.intWrapper($from).until($until).by($by)" ⇒ RangeGenerator(from, until, by, q"false")
    case Block(inits, expr)                                ⇒ range(expr).withInits(inits: _*)
    case _ ⇒
      val rangeVar = c.fresh(newTermName("range$"))
      val init = q"val $rangeVar = $t: @speed.dontfold"
      RangeGenerator(q"$rangeVar.start", q"$rangeVar.end", q"$rangeVar.step", q"$rangeVar.isInclusive")
        .withInits(init)
  }

  lazy val impureAnn = c.mirror.staticClass("speed.impure")
  def isPure(tpe: Type): Boolean = tpe match {
    case ann: AnnotatedType ⇒ !ann.annotations.exists(_.tpe.typeSymbol == impureAnn)
    case _                  ⇒ true // bold assumption
  }

  def closure1(fTree: Tree, pure: Boolean = true): Closure = fTree match {
    // look for impure annotation
    case q"$t: $tpt"                    ⇒ closure1(t, pure && isPure(fTree.tpe))
    // try to find literal anonymous functions
    case q"( $i => $body )"             ⇒ Closure(i.name, q"{ ${cleanBody(i, body)} }: @speed.dontfold()", q"", pure)
    //case q"( ($i: ${ _ }) => $body )"   ⇒ AnonFunc(i.asInstanceOf[ValDef].name, q"{ $body }", q"")
    // this matches partial evaluation (like `println _`)
    case Block(Nil, q"( $i => $body )") ⇒ Closure(i.name, q"{ ${cleanBody(i, body)} }: @speed.dontfold()", q"", pure)
    case _ ⇒
      c.warning(fTree.pos, s"Couldn't extract anonymous function implementation here. '$fTree' '${fTree.productPrefix}'")
      val fun = c.fresh(newTermName("funInit"))
      val iVar = c.fresh(newTermName("i"))
      Closure(iVar, q"$fun($iVar)", q"val $fun = $fTree", pure)
  }

  /**
   *  Makes sure that references to the parameters of a lambda gets detached from the parameters.
   *  Otherwise, the references won't be correctly re-resolved (to whatever the variable name was now bound to)
   *  when the body is typechecked. Leaving this out will lead to ugly compiler crashes in the backend.
   */
  def cleanBody(valDef: ValDef, body: Tree): Tree = new ClosureCleaner(Set(valDef.symbol)).transform(body)
  def cleanBody(valDef1: ValDef, valDef2: ValDef, body: Tree): Tree = new ClosureCleaner(Set(valDef1.symbol, valDef2.symbol)).transform(body)
  class ClosureCleaner(candidates: Set[Symbol]) extends Transformer {
    override def transform(t: Tree): Tree = t match {
      // make sure to make a clean copy of the ident if the ident refers to a former parameter of the lambda
      case i: Ident if candidates(i.symbol) ⇒ Ident(i.name)
      case _                                ⇒ super.transform(t)
    }
  }

  def closure2(fTree: Tree, pure: Boolean = true): Closure2 =
    fTree match {
      // look for impure annotation
      case q"$t: $tpt"                            ⇒ closure2(t, pure && isPure(fTree.tpe))
      // try to find literal anonymous functions
      case q"( ($i1, $i2) => $body )"             ⇒ Closure2(i1.name, i2.name, q"{ ${cleanBody(i1, i2, body)} }: @speed.dontfold()", q"", pure)
      // this matches partial evaluation (like `println _`)
      case Block(Nil, q"( ($i1, $i2) => $body )") ⇒ Closure2(i1.name, i2.name, q"{ ${cleanBody(i1, i2, body)} }: @speed.dontfold()", q"", pure)
      case _ ⇒
        val fun = c.fresh(newTermName("funInit"))
        Closure2("i1", "i2", q"$fun(i1, i2)", q"val $fun = $fTree", pure)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy