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

spire.macros.Syntax.scala Maven / Gradle / Ivy

The newest version!
package spire.macrosk

import scala.reflect.macros.Context

object Syntax {
  // used to give our labels, vars a somewhat unique identifier
  var n: Int = 0

  def cforMacro[A:c.WeakTypeTag](c:Context)(init:c.Expr[A])
     (test:c.Expr[A => Boolean], next:c.Expr[A => A])
     (body:c.Expr[A => Unit]): c.Expr[Unit] = {
    import c.universe._

    val c.WeakTypeTag(tpe) = implicitly[c.WeakTypeTag[A]]

    // it would be good to do something smarter here
    n = (n + 1) % 100000

    val a = newTermName("a%d" format n)
    val w = newTermName("w%d" format n)

    val tailrec = newTermName("tailrec")

    val importTailrec = Import(
      Select(Ident("scala"), newTermName("annotation")),
      List(ImportSelector(tailrec, 1161, tailrec, 1161)))

    // TODO: why can't i get the freaking tailrec working??? ARGHGGH!!

    //val mods = Modifiers(NoFlags, tpnme.EMPTY,
    //  List(Apply(Select(New(Ident(tailrec)), nme.CONSTRUCTOR), List())))
    val mods = Modifiers(NoFlags, tpnme.EMPTY, List())

    val param = List(ValDef(Modifiers(Flag.PARAM), a, TypeTree(tpe), EmptyTree))

    val t = Block(
      List(
        //importTailrec,
        DefDef(mods, w, List(), List(param), Ident(newTypeName("Unit")),
          If(Apply(test.tree, List(Ident(a))),
            Block(
              List(Apply(body.tree, List(Ident(a)))),
              Apply(Ident(w), List(Apply(next.tree, List(Ident(a)))))),
            Literal(Constant(()))))),
      Apply(Ident(w), List(init.tree)))

    new Util[c.type](c).inlineAndReset[Unit](t)
  }

  class Util[C <: Context with Singleton](val c:C) {
    import c.universe._

    def die(msg:String) = c.abort(c.enclosingPosition, msg)

    def inlineAndReset[T](tree: Tree): c.Expr[T] =
      c.Expr[T](c resetAllAttrs inlineApplyRecursive(tree))

    def inlineApplyRecursive(tree: Tree): Tree = {
      val ApplyName = newTermName("apply")

      class InlineTerm(name:TermName, value:Tree) extends Transformer {
        override def transform(tree: Tree): Tree = tree match {
          case Ident(`name`) => value
          case _ => super.transform(tree)
        }
      }

      object InlineApply extends Transformer {
        def inlineTerms(params: List[Tree], body: Tree, args: List[Tree]): Tree = {
          if (params.length != args.length)
            die("bad arity: %s vs %s" format (params.length, args.length))

          params.zip(args).foldLeft(body) {
            case (body, (ValDef(_, name, _, _), arg)) => {
              new InlineTerm(name, arg).transform(body)
            }
          }
        }

        override def transform(tree: Tree): Tree = tree match {
          case Apply(Select(Function(params, body), ApplyName), args) =>
            inlineTerms(params, body, args)

          case Apply(Function(params, body), args) =>
            inlineTerms(params, body, args)

          case _ =>
            super.transform(tree)
        }
      }

      InlineApply.transform(tree)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy