Skip to content

Commit

Permalink
dumping experimental code for collection-like DSLs
Browse files Browse the repository at this point in the history
  • Loading branch information
ochafik committed Mar 7, 2013
1 parent ece8b00 commit 782b62d
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 0 deletions.
50 changes: 50 additions & 0 deletions 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)
}
}
135 changes: 135 additions & 0 deletions 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)
})
}
}
9 changes: 9 additions & 0 deletions 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)

26 changes: 26 additions & 0 deletions 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)
}
21 changes: 21 additions & 0 deletions 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)
*/
}

0 comments on commit 782b62d

Please sign in to comment.