Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
dumping experimental code for collection-like DSLs
- Loading branch information
Showing
5 changed files
with
241 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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) | |||
} | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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) | |||
}) | |||
} | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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) | |||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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) | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -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) | |||
*/ | |||
} |