diff --git a/DSL/ReifiedFilterMonadic.scala b/DSL/ReifiedFilterMonadic.scala new file mode 100644 index 00000000..5db1f815 --- /dev/null +++ b/DSL/ReifiedFilterMonadic.scala @@ -0,0 +1,50 @@ +package scalaxy.dsl + +import scala.language.experimental.macros +import scala.collection.GenTraversableOnce +import scala.collection.generic.CanBuildFrom + +trait ReifiedFilterMonadic[A, Repr] { + self => + + def reifiedForeach[U]( + f: ReifiedFunction[A, U], + filters: List[ReifiedFunction[A, Boolean]]): Unit + + def reifiedFlatMap[B, That]( + f: ReifiedFunction[A, GenTraversableOnce[B]], + filters: List[ReifiedFunction[A, Boolean]])( + implicit bf: CanBuildFrom[Repr, B, That]): That + + def reifiedFilters: List[ReifiedFunction[A, Boolean]] = Nil + + def foreach[U](f: A => U): Unit = + macro ReifiedFilterMonadicMacros.foreachImpl[A, Repr, U] + + def withFilter(f: A => Boolean): ReifiedFilterMonadic[A, Repr] = + macro ReifiedFilterMonadicMacros.withFilterImpl[A, Repr] + + def flatMap[B, That]( + f: A => GenTraversableOnce[B])( + implicit bf: CanBuildFrom[Repr, B, That]): That = + macro ReifiedFilterMonadicMacros.flatMapImpl[A, Repr, B, That] + + def withFilters(filters: List[ReifiedFunction[A, Boolean]]) = + new WithFilters(filters) + + class WithFilters(filters: List[ReifiedFunction[A, Boolean]]) + extends ReifiedFilterMonadic[A, Repr] { + override def reifiedFilters = filters + override def reifiedForeach[U]( + f: ReifiedFunction[A, U], + filters: List[ReifiedFunction[A, Boolean]]) { + self.reifiedForeach(f, filters) + } + + override def reifiedFlatMap[B, That]( + f: ReifiedFunction[A, GenTraversableOnce[B]], + filters: List[ReifiedFunction[A, Boolean]])( + implicit bf: CanBuildFrom[Repr, B, That]): That = + self.reifiedFlatMap(f, filters) + } +} diff --git a/DSL/ReifiedFilterMonadicMacros.scala b/DSL/ReifiedFilterMonadicMacros.scala new file mode 100644 index 00000000..74b68fbe --- /dev/null +++ b/DSL/ReifiedFilterMonadicMacros.scala @@ -0,0 +1,135 @@ +package scalaxy.dsl + +import scala.language.experimental.macros +import scala.reflect.macros.Context + +import scala.collection.GenTraversableOnce +import scala.collection.generic.CanBuildFrom +import scala.collection.breakOut + +import scala.reflect.runtime.{ universe => ru } + +object ReifiedFilterMonadicMacros { + def reifyFunction[A : c.WeakTypeTag, B : c.WeakTypeTag] + (c: Context) + (f: c.Expr[A => B]) + : c.Expr[ReifiedFunction[A, B]] = + { + import c.universe._ + + val tf = c.typeCheck(f.tree) + + var definedSymbols = Set[Symbol]() + var referredSymbols = Set[Symbol]() + new Traverser { + override def traverse(tree: Tree) { + val sym = tree.symbol + if (sym != NoSymbol) { + tree match { + case _: DefTree => + definedSymbols += sym + case Ident(_) => + referredSymbols += sym + case _: RefTree => + c.warning( + tree.pos, + s"Maybe an unsupported reference type: $tree (${showRaw(tree)})") + case _ => + } + } + super.traverse(tree) + } + }.traverse(tf) + + val capturedSymbols: Map[Symbol, String] = + ( + for (capturedSymbol <- (referredSymbols -- definedSymbols)) yield { + capturedSymbol -> c.fresh(capturedSymbol.name.toString) + } + ).toMap + + val ttf = c.Expr[A => B]( + new Transformer { + object CapturedSymbol { + def unapply(tree: Tree) = tree match { + case Ident(_) => + capturedSymbols.get(tree.symbol).map(Some(_)).getOrElse(None) + case _ => + None + } + } + override def transform(tree: Tree): Tree = tree match { + case CapturedSymbol(newName) => + Ident(newName: TermName) + case _ => + super.transform(tree) + } + }.transform(tf) + ) + + + val capturesExpr = c.Expr[Map[String, () => Any]]( + Apply( + reify({ Map }).tree, + for ((capturedSymbol, newName) <- capturedSymbols.toList) yield { + val s = c.literal(newName) + val v = c.Expr[Any](Ident(capturedSymbol)) + reify((s.splice, () => v.splice)).tree + } + ) + ) + + val reifiedTree = c.Expr[ru.Expr[ru.Tree]](c.reifyTree( + treeBuild.mkRuntimeUniverseRef, + EmptyTree, + ttf.tree + )) + + reify({ + new ReifiedFunction( + ttf.splice, + capturesExpr.splice, + reifiedTree.splice.tree.asInstanceOf[ru.Function] + ) + }) + } + + + def foreachImpl[A, Repr, U](c: Context)(f: c.Expr[A => U]): c.Expr[Unit] = + { + import c.universe._ + val reifiedFunction = reifyFunction(c)(f) + val colExpr = c.prefix.asInstanceOf[c.Expr[ReifiedFilterMonadic[A, Repr]]] + reify({ + val col = colExpr.splice + col.reifiedForeach(reifiedFunction.splice, col.reifiedFilters) + }) + } + + def withFilterImpl[A, Repr](c: Context)(f: c.Expr[A => Boolean]) + : c.Expr[ReifiedFilterMonadic[A, Repr]] = + { + import c.universe._ + val reifiedFunction = reifyFunction(c)(f) + val colExpr = c.prefix.asInstanceOf[c.Expr[ReifiedFilterMonadic[A, Repr]]] + reify({ + val col = colExpr.splice + col.withFilters(col.reifiedFilters :+ reifiedFunction.splice): ReifiedFilterMonadic[A, Repr] + }) + } + + def flatMapImpl[A, Repr, B, That] + (c: Context) + (f: c.Expr[A => GenTraversableOnce[B]]) + (bf: c.Expr[CanBuildFrom[Repr, B, That]]) + : c.Expr[That] = + { + import c.universe._ + val reifiedFunction = reifyFunction(c)(f) + val colExpr = c.prefix.asInstanceOf[c.Expr[ReifiedFilterMonadic[A, Repr]]] + reify({ + val col = colExpr.splice + col.reifiedFlatMap(reifiedFunction.splice, col.reifiedFilters)(bf.splice) + }) + } +} diff --git a/DSL/ReifiedFunction.scala b/DSL/ReifiedFunction.scala new file mode 100644 index 00000000..5f791a87 --- /dev/null +++ b/DSL/ReifiedFunction.scala @@ -0,0 +1,9 @@ +package scalaxy.dsl + +import scala.reflect.runtime.universe.{ Symbol, Function } + +case class ReifiedFunction[A, B]( + function: A => B, + captures: Map[String, () => Any], + tree: Function) + diff --git a/DSL/Select.scala b/DSL/Select.scala new file mode 100644 index 00000000..d3f8f174 --- /dev/null +++ b/DSL/Select.scala @@ -0,0 +1,26 @@ +package scalaxy.dsl + +import scala.reflect.runtime.universe.{ Symbol, Function } + +import scala.collection.GenTraversableOnce +import scala.collection.generic.CanBuildFrom +class Select[A](val from: A) extends ReifiedFilterMonadic[A, Select[A]] { + def reifiedForeach[U]( + f: ReifiedFunction[A, U], + filters: List[ReifiedFunction[A, Boolean]]): Unit = { + println(s"f = $f, filters = $filters") + } + + def reifiedFlatMap[B, That]( + f: ReifiedFunction[A, GenTraversableOnce[B]], + filters: List[ReifiedFunction[A, Boolean]])( + implicit bf: CanBuildFrom[Select[A], B, That]): That = { + println(s"f = $f, filters = $filters") + val b = bf() + b.result() + } +} + +object Select { + def apply[A](from: A) = new Select(from) +} diff --git a/DSL/Test.scala b/DSL/Test.scala new file mode 100644 index 00000000..eb37fc3c --- /dev/null +++ b/DSL/Test.scala @@ -0,0 +1,21 @@ +package scalaxy.dsl + +case class Table(name: String) + +/* +scalac ReifiedFilterMonadicMacros.scala ReifiedFunction.scala ReifiedFilterMonadic.scala && scalac Select.scala Test.scala && scala Test +*/ +object Test extends App +{ + val table = Table("users") + val q = for (row <- Select(table)) { + println(row) + } + + /* +case class ReifiedFunction[A, B]( + function: A => B, + captures: Map[Symbol, () => Any], + tree: Function) +*/ +}