-
-
Notifications
You must be signed in to change notification settings - Fork 609
/
RewriteBooleans.scala
74 lines (65 loc) · 2.77 KB
/
RewriteBooleans.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package scala.slick.compiler
import scala.slick.ast._
import Util.nodeToNodeOps
import TypeUtil._
/** For SQL back-ends which do not support real boolean types for fields and
* general expressions but which do have special boolean expressions and
* operators, this phase injects conversions between fake and real boolean
* values.
*
* The default for booleans in the AST is to use the fake type. There are
* specific places where a real boolean is required or produced, so we
* inject a call to ToRealBoolean or ToFakeBoolean as needed. */
class RewriteBooleans extends Phase {
import RewriteBooleans._
val name = "rewriteBooleans"
def apply(state: CompilerState) =
state.map { n => ClientSideOp.mapServerSide(n)(rewriteRec) }
def rewriteRec(n: Node): Node = {
val n2 = n.nodeMapChildren(rewriteRec, true)
val n3 = rewrite(n2)
if(n3 ne n2) logger.debug(s"Rewriting $n2 to $n3")
n3
}
/** Rewrite a single Node. This method can be overridden in subclasses to
* change the situations in which conversions are applied. */
def rewrite(n: Node): Node = n match {
// These boolean operators accept and produce real booleans
case Apply(sym @ (Library.And | Library.Or | Library.Not), ch) =>
toFake(Apply(sym, ch.map(n => toReal(n)))(n.nodeType))
// All other boolean-typed operators produce real booleans but accept fake ones
case Apply(sym, ch) :@ tpe if isBooleanLike(tpe) =>
toFake(Apply(sym, ch)(n.nodeType))
// Where clauses, join conditions and case clauses need real boolean predicates
case n @ Comprehension(_, where, _, _, _, _, _) =>
n.copy(where = where.map(toReal)).nodeTyped(n.nodeType)
case n @ Join(_, _, _, _, _, on) =>
n.copy(on = toReal(on)).nodeTyped(n.nodeType)
case n @ IfThen(left, _) =>
n.copy(left = toReal(left))
case n => n
}
/** Create a conversion to a fake boolean, cancelling out an existing
* conversion to a real boolean. */
def toFake(n: Node) = n match {
case ToRealBoolean(ch) => ch
case _ => ToFakeBoolean.typed(n.nodeType, n)
}
/** Create a conversion to a real boolean, cancelling out an existing
* conversion to a fake boolean. */
def toReal(n: Node) = n match {
case ToFakeBoolean(ch) => ch
case _ => ToRealBoolean.typed(n.nodeType, n)
}
/** Check if a type is equivalent to the Scala Boolean type or a (possibly
* nested) Option of that type. */
def isBooleanLike(t: Type): Boolean = t match {
case t: TypedType[_] if t.scalaType == ScalaBaseType.booleanType => true
case t: OptionType => isBooleanLike(t.elementType)
case _ => false
}
}
object RewriteBooleans {
val ToFakeBoolean = new FunctionSymbol("RewriteBooleans.ToFakeBoolean")
val ToRealBoolean = new FunctionSymbol("RewriteBooleans.ToRealBoolean")
}