Skip to content

Commit

Permalink
Merge branch 'master' into fix-667
Browse files Browse the repository at this point in the history
  • Loading branch information
mxl authored Dec 25, 2016
2 parents a981c2a + 600cfef commit 5ceb586
Show file tree
Hide file tree
Showing 18 changed files with 282 additions and 90 deletions.
11 changes: 4 additions & 7 deletions quill-core/src/main/scala/io/getquill/MirrorIdiom.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,10 @@ class MirrorIdiom extends Idiom {
}

implicit def optionOperationTokenizer(implicit liftTokenizer: Tokenizer[Lift]): Tokenizer[OptionOperation] = Tokenizer[OptionOperation] {
case q: OptionOperation =>
val method = q.t match {
case OptionMap => "map"
case OptionForall => "forall"
case OptionExists => "exists"
}
stmt"${q.ast.token}.${method.token}((${q.alias.token}) => ${q.body.token})"
case OptionMap(ast, alias, body) => stmt"${ast.token}.map((${alias.token}) => ${body.token})"
case OptionForall(ast, alias, body) => stmt"${ast.token}.forall((${alias.token}) => ${body.token})"
case OptionExists(ast, alias, body) => stmt"${ast.token}.exists((${alias.token}) => ${body.token})"
case OptionContains(ast, body) => stmt"${ast.token}.contains(${body.token})"
}

implicit val joinTypeTokenizer: Tokenizer[JoinType] = Tokenizer[JoinType] {
Expand Down
6 changes: 5 additions & 1 deletion quill-core/src/main/scala/io/getquill/ast/Ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ case class Ident(name: String) extends Ast

case class Property(ast: Ast, name: String) extends Ast

case class OptionOperation(t: OptionOperationType, ast: Ast, alias: Ident, body: Ast) extends Ast
sealed trait OptionOperation extends Ast
case class OptionMap(ast: Ast, alias: Ident, body: Ast) extends OptionOperation
case class OptionForall(ast: Ast, alias: Ident, body: Ast) extends OptionOperation
case class OptionExists(ast: Ast, alias: Ident, body: Ast) extends OptionOperation
case class OptionContains(ast: Ast, body: Ast) extends OptionOperation

case class If(condition: Ast, `then`: Ast, `else`: Ast) extends Ast

Expand Down

This file was deleted.

38 changes: 27 additions & 11 deletions quill-core/src/main/scala/io/getquill/ast/StatefulTransformer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ trait StatefulTransformer[T] {

def apply(e: Ast): (Ast, StatefulTransformer[T]) =
e match {
case e: Query => apply(e)
case e: Operation => apply(e)
case e: Action => apply(e)
case e: Value => apply(e)
case e: Assignment => apply(e)
case e: Ident => (e, this)
case e: Query => apply(e)
case e: Operation => apply(e)
case e: Action => apply(e)
case e: Value => apply(e)
case e: Assignment => apply(e)
case e: Ident => (e, this)
case e: OptionOperation => apply(e)

case Function(a, b) =>
val (bt, btt) = apply(b)
Expand All @@ -25,11 +26,6 @@ trait StatefulTransformer[T] {
val (bt, btt) = apply(b)(_.apply)
(Infix(a, bt), btt)

case OptionOperation(t, a, b, c) =>
val (at, att) = apply(a)
val (ct, ctt) = att.apply(c)
(OptionOperation(t, at, b, ct), ctt)

case If(a, b, c) =>
val (at, att) = apply(a)
val (bt, btt) = att.apply(b)
Expand All @@ -55,6 +51,26 @@ trait StatefulTransformer[T] {
case o: Ordering => (o, this)
}

def apply(o: OptionOperation): (OptionOperation, StatefulTransformer[T]) =
o match {
case OptionMap(a, b, c) =>
val (at, att) = apply(a)
val (ct, ctt) = att.apply(c)
(OptionMap(at, b, ct), ctt)
case OptionForall(a, b, c) =>
val (at, att) = apply(a)
val (ct, ctt) = att.apply(c)
(OptionForall(at, b, ct), ctt)
case OptionExists(a, b, c) =>
val (at, att) = apply(a)
val (ct, ctt) = att.apply(c)
(OptionExists(at, b, ct), ctt)
case OptionContains(a, c) =>
val (at, att) = apply(a)
val (ct, ctt) = att.apply(c)
(OptionContains(at, ct), ctt)
}

def apply(e: Query): (Query, StatefulTransformer[T]) =
e match {
case e: Entity => (e, this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,31 @@ trait StatelessTransformer {

def apply(e: Ast): Ast =
e match {
case e: Query => apply(e)
case e: Operation => apply(e)
case e: Action => apply(e)
case e: Value => apply(e)
case e: Assignment => apply(e)
case Function(params, body) => Function(params, apply(body))
case e: Ident => e
case Property(a, name) => Property(apply(a), name)
case Infix(a, b) => Infix(a, b.map(apply))
case OptionOperation(t, a, b, c) => OptionOperation(t, apply(a), b, apply(c))
case If(a, b, c) => If(apply(a), apply(b), apply(c))
case e: Dynamic => e
case e: Lift => e
case e: QuotedReference => e
case Block(statements) => Block(statements.map(apply))
case Val(name, body) => Val(name, apply(body))
case o: Ordering => o
case e: Query => apply(e)
case e: Operation => apply(e)
case e: Action => apply(e)
case e: Value => apply(e)
case e: Assignment => apply(e)
case Function(params, body) => Function(params, apply(body))
case e: Ident => e
case Property(a, name) => Property(apply(a), name)
case Infix(a, b) => Infix(a, b.map(apply))
case e: OptionOperation => apply(e)
case If(a, b, c) => If(apply(a), apply(b), apply(c))
case e: Dynamic => e
case e: Lift => e
case e: QuotedReference => e
case Block(statements) => Block(statements.map(apply))
case Val(name, body) => Val(name, apply(body))
case o: Ordering => o
}

def apply(o: OptionOperation): OptionOperation =
o match {
case OptionMap(a, b, c) => OptionMap(apply(a), b, apply(c))
case OptionForall(a, b, c) => OptionForall(apply(a), b, apply(c))
case OptionExists(a, b, c) => OptionExists(apply(a), b, apply(c))
case OptionContains(a, b) => OptionContains(apply(a), apply(b))
}

def apply(e: Query): Query =
Expand Down
15 changes: 12 additions & 3 deletions quill-core/src/main/scala/io/getquill/norm/BetaReduction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ case class BetaReduction(map: collection.Map[Ast, Ast])
case Function(params, body) =>
Function(params, BetaReduction(map -- params)(body))

case OptionOperation(t, a, b, c) =>
OptionOperation(t, apply(a), b, BetaReduction(map - b)(c))

case Block(statements) =>
val vals = statements.collect { case x: Val => x.name -> x.body }
BetaReduction(map ++ vals)(statements.last)
Expand All @@ -43,6 +40,18 @@ case class BetaReduction(map: collection.Map[Ast, Ast])
super.apply(other)
}

override def apply(o: OptionOperation) =
o match {
case OptionMap(a, b, c) =>
OptionMap(apply(a), b, BetaReduction(map - b)(c))
case OptionForall(a, b, c) =>
OptionForall(apply(a), b, BetaReduction(map - b)(c))
case OptionExists(a, b, c) =>
OptionExists(apply(a), b, BetaReduction(map - b)(c))
case other =>
super.apply(other)
}

override def apply(e: Assignment) =
e match {
case Assignment(alias, prop, value) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package io.getquill.norm

import io.getquill.ast.Ast
import io.getquill.ast.OptionOperation
import io.getquill.ast.StatelessTransformer
import io.getquill.ast._

object FlattenOptionOperation extends StatelessTransformer {

override def apply(ast: Ast) =
ast match {
case OptionOperation(t, ast, alias, body) =>
case OptionMap(ast, alias, body) =>
BetaReduction(body, alias -> ast)
case OptionForall(ast, alias, body) =>
BetaReduction(body, alias -> ast)
case OptionExists(ast, alias, body) =>
BetaReduction(body, alias -> ast)
case OptionContains(ast, body) =>
BinaryOperation(ast, EqualityOperator.`==`, body)
case other =>
super.apply(ast)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,24 @@ case class FreeVariables(state: State)
case f @ Function(params, body) =>
val (_, t) = FreeVariables(State(state.seen ++ params, state.free))(body)
(f, FreeVariables(State(state.seen, state.free ++ t.state.free)))
case OptionOperation(t, a, b, c) =>
(ast, free(a, b, c))
case q @ Foreach(a, b, c) =>
(q, free(a, b, c))
case other =>
super.apply(other)
}

override def apply(o: OptionOperation): (OptionOperation, StatefulTransformer[State]) =
o match {
case q @ OptionMap(a, b, c) =>
(q, free(a, b, c))
case q @ OptionForall(a, b, c) =>
(q, free(a, b, c))
case q @ OptionExists(a, b, c) =>
(q, free(a, b, c))
case other =>
super.apply(other)
}

override def apply(e: Assignment): (Assignment, StatefulTransformer[State]) =
e match {
case Assignment(a, b, c) =>
Expand Down
11 changes: 6 additions & 5 deletions quill-core/src/main/scala/io/getquill/quotation/Liftables.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ trait Liftables {
case ast: Ordering => orderingLiftable(ast)
case ast: Lift => liftLiftable(ast)
case ast: Assignment => assignmentLiftable(ast)
case ast: OptionOperation => optionOperationLiftable(ast)
case Val(name, body) => q"$pack.Val($name, $body)"
case Block(statements) => q"$pack.Block($statements)"
case Property(a, b) => q"$pack.Property($a, $b)"
Expand All @@ -27,17 +28,17 @@ trait Liftables {
case BinaryOperation(a, b, c) => q"$pack.BinaryOperation($a, $b, $c)"
case UnaryOperation(a, b) => q"$pack.UnaryOperation($a, $b)"
case Infix(a, b) => q"$pack.Infix($a, $b)"
case OptionOperation(a, b, c, d) => q"$pack.OptionOperation($a, $b, $c, $d)"
case If(a, b, c) => q"$pack.If($a, $b, $c)"
case Dynamic(tree: Tree) if (tree.tpe <:< c.weakTypeOf[CoreDsl#Quoted[Any]]) => q"$tree.ast"
case Dynamic(tree: Tree) => q"$pack.Constant($tree)"
case QuotedReference(tree: Tree, ast) => q"$ast"
}

implicit val optionOperationTypeLiftable: Liftable[OptionOperationType] = Liftable[OptionOperationType] {
case OptionMap => q"$pack.OptionMap"
case OptionForall => q"$pack.OptionForall"
case OptionExists => q"$pack.OptionExists"
implicit val optionOperationLiftable: Liftable[OptionOperation] = Liftable[OptionOperation] {
case OptionMap(a, b, c) => q"$pack.OptionMap($a,$b,$c)"
case OptionForall(a, b, c) => q"$pack.OptionForall($a,$b,$c)"
case OptionExists(a, b, c) => q"$pack.OptionExists($a,$b,$c)"
case OptionContains(a, b) => q"$pack.OptionContains($a,$b)"
}

implicit val binaryOperatorLiftable: Liftable[BinaryOperator] = Liftable[BinaryOperator] {
Expand Down
8 changes: 5 additions & 3 deletions quill-core/src/main/scala/io/getquill/quotation/Parsing.scala
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,13 @@ trait Parsing {

val optionOperationParser: Parser[OptionOperation] = Parser[OptionOperation] {
case q"$o.map[$t]({($alias) => $body})" if (is[Option[Any]](o)) =>
OptionOperation(OptionMap, astParser(o), identParser(alias), astParser(body))
OptionMap(astParser(o), identParser(alias), astParser(body))
case q"$o.forall({($alias) => $body})" if (is[Option[Any]](o)) =>
OptionOperation(OptionForall, astParser(o), identParser(alias), astParser(body))
OptionForall(astParser(o), identParser(alias), astParser(body))
case q"$o.exists({($alias) => $body})" if (is[Option[Any]](o)) =>
OptionOperation(OptionExists, astParser(o), identParser(alias), astParser(body))
OptionExists(astParser(o), identParser(alias), astParser(body))
case q"$o.contains[$t]($body)" if (is[Option[Any]](o)) =>
OptionContains(astParser(o), astParser(body))
}

val propertyParser: Parser[Ast] = Parser[Ast] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,23 @@ trait Unliftables {
case valueUnliftable(ast) => ast
case identUnliftable(ast) => ast
case orderingUnliftable(ast) => ast
case optionOperationUnliftable(ast) => ast
case q"$pack.Property.apply(${ a: Ast }, ${ b: String })" => Property(a, b)
case q"$pack.Function.apply(${ a: List[Ident] }, ${ b: Ast })" => Function(a, b)
case q"$pack.FunctionApply.apply(${ a: Ast }, ${ b: List[Ast] })" => FunctionApply(a, b)
case q"$pack.BinaryOperation.apply(${ a: Ast }, ${ b: BinaryOperator }, ${ c: Ast })" => BinaryOperation(a, b, c)
case q"$pack.UnaryOperation.apply(${ a: UnaryOperator }, ${ b: Ast })" => UnaryOperation(a, b)
case q"$pack.Aggregation.apply(${ a: AggregationOperator }, ${ b: Ast })" => Aggregation(a, b)
case q"$pack.Infix.apply(${ a: List[String] }, ${ b: List[Ast] })" => Infix(a, b)
case q"$pack.OptionOperation.apply(${ a: OptionOperationType }, ${ b: Ast }, ${ c: Ident }, ${ d: Ast })" => OptionOperation(a, b, c, d)
case q"$pack.If.apply(${ a: Ast }, ${ b: Ast }, ${ c: Ast })" => If(a, b, c)
case q"$tree.ast" => Dynamic(tree)
}

implicit val optionOperationTypeUnliftable: Unliftable[OptionOperationType] = Unliftable[OptionOperationType] {
case q"$pack.OptionMap" => OptionMap
case q"$pack.OptionForall" => OptionForall
case q"$pack.OptionExists" => OptionExists
implicit val optionOperationUnliftable: Unliftable[OptionOperation] = Unliftable[OptionOperation] {
case q"$pack.OptionMap.apply(${ a: Ast }, ${ b: Ident }, ${ c: Ast })" => OptionMap(a, b, c)
case q"$pack.OptionForall.apply(${ a: Ast }, ${ b: Ident }, ${ c: Ast })" => OptionForall(a, b, c)
case q"$pack.OptionExists.apply(${ a: Ast }, ${ b: Ident }, ${ c: Ast })" => OptionExists(a, b, c)
case q"$pack.OptionContains.apply(${ a: Ast }, ${ b: Ident })" => OptionContains(a, b)
}

implicit def listUnliftable[T](implicit u: Unliftable[T]): Unliftable[List[T]] = Unliftable[List[T]] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,38 @@ class StatefulTransformerSpec extends Spec {
}
}

"option operation" in {
val ast: Ast = OptionOperation(OptionMap, Ident("a"), Ident("b"), Ident("c"))
Subject(Nil, Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) match {
case (at, att) =>
at mustEqual OptionOperation(OptionMap, Ident("a'"), Ident("b"), Ident("c'"))
att.state mustEqual List(Ident("a"), Ident("c"))
"option operation" - {
"map" in {
val ast: Ast = OptionMap(Ident("a"), Ident("b"), Ident("c"))
Subject(Nil, Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) match {
case (at, att) =>
at mustEqual OptionMap(Ident("a'"), Ident("b"), Ident("c'"))
att.state mustEqual List(Ident("a"), Ident("c"))
}
}
"forall" in {
val ast: Ast = OptionForall(Ident("a"), Ident("b"), Ident("c"))
Subject(Nil, Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) match {
case (at, att) =>
at mustEqual OptionForall(Ident("a'"), Ident("b"), Ident("c'"))
att.state mustEqual List(Ident("a"), Ident("c"))
}
}
"exists" in {
val ast: Ast = OptionExists(Ident("a"), Ident("b"), Ident("c"))
Subject(Nil, Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) match {
case (at, att) =>
at mustEqual OptionExists(Ident("a'"), Ident("b"), Ident("c'"))
att.state mustEqual List(Ident("a"), Ident("c"))
}
}
"contains" in {
val ast: Ast = OptionContains(Ident("a"), Ident("c"))
Subject(Nil, Ident("a") -> Ident("a'"), Ident("c") -> Ident("c'"))(ast) match {
case (at, att) =>
at mustEqual OptionContains(Ident("a'"), Ident("c'"))
att.state mustEqual List(Ident("a"), Ident("c"))
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,27 @@ class StatelessTransformerSpec extends Spec {
Infix(List("test"), List(Ident("a'"), Ident("b'")))
}

"option operation" in {
val ast: Ast = OptionOperation(OptionForall, Ident("a"), Ident("b"), Ident("c"))
Subject(Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) mustEqual
OptionOperation(OptionForall, Ident("a'"), Ident("b"), Ident("c'"))
"option operation" - {
"map" in {
val ast: Ast = OptionMap(Ident("a"), Ident("b"), Ident("c"))
Subject(Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) mustEqual
OptionMap(Ident("a'"), Ident("b"), Ident("c'"))
}
"forall" in {
val ast: Ast = OptionForall(Ident("a"), Ident("b"), Ident("c"))
Subject(Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) mustEqual
OptionForall(Ident("a'"), Ident("b"), Ident("c'"))
}
"exists" in {
val ast: Ast = OptionExists(Ident("a"), Ident("b"), Ident("c"))
Subject(Ident("a") -> Ident("a'"), Ident("b") -> Ident("b'"), Ident("c") -> Ident("c'"))(ast) mustEqual
OptionExists(Ident("a'"), Ident("b"), Ident("c'"))
}
"contains" in {
val ast: Ast = OptionContains(Ident("a"), Ident("c"))
Subject(Ident("a") -> Ident("a'"), Ident("c") -> Ident("c'"))(ast) mustEqual
OptionContains(Ident("a'"), Ident("c'"))
}
}

"if" in {
Expand Down
Loading

0 comments on commit 5ceb586

Please sign in to comment.