-
Notifications
You must be signed in to change notification settings - Fork 2
/
Compiler.scala
152 lines (134 loc) · 4.87 KB
/
Compiler.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
object C extends Symantics {
// Our Trees
sealed trait Exp {
val prec: Int
override def toString = this match {
case Var(i) => s"v$i"
case Cst(v) => v.toString
case Lam(f) => s"(λ $f)"
case Fix(f) => s"(θ $f)"
case App(f, v) => s"${wrp(f)} ${wrp(v)}"
case If(c,t,e) => s"if $c then $t else $e"
case Add(l,r) => s"${wrp(l)} + ${wrp(r)}"
case Mul(l,r) => s"${wrp(l)} * ${wrp(r)}"
case Leq(l,r) => s"${wrp(l)} <= ${wrp(r)}"
case Hole(x) => s"[$x]"
case _: PH => "PH"
}
def wrp(x: Exp) =
if (this.prec > x.prec) s"($x)"
else x.toString
}
sealed trait Single extends Exp { val prec = Int.MaxValue }
sealed trait Value extends Exp
// Placeholder to pose variables
class PH extends Single
// De-Brujin encoded var
case class Var(n: Int) extends Single
case class Cst(v: Any) extends Value with Single
case class Lam(f: Exp) extends Value with Single
// Note that a fix is also a lambda for De-Brujin
case class Fix(f: Exp) extends Single
case class App(f: Exp, v: Exp) extends Exp { val prec = 4 }
case class If(c: Exp, t: Exp, e: Exp) extends Exp { val prec = 0 }
case class Add(lhs: Exp, rhs: Exp) extends Exp { val prec = 2 }
case class Mul(lhs: Exp, rhs: Exp) extends Exp { val prec = 3 }
case class Leq(lhs: Exp, rhs: Exp) extends Exp { val prec = 1 }
// Dummy class to show holes in AST
case class Hole(x: Exp) extends Single
type Repr[D,S] = Exp
def int(c: Int): Repr[Int,Int] = Cst(c)
def bool(c: Boolean): Repr[Boolean,Boolean] = Cst(c)
def lam[A, B](f: SFun[A,B]): Repr[A => B, SFun[A,B]] = {
val ph = new PH
Lam(resolvePH(ph, f(ph)))
}
def app[A, B](f: RLam[A,B])(v: Repr[A,A]): Repr[B,B] = App(f,v)
def _if[D,S](c: Repr[Boolean,Boolean])(t: =>Repr[D,S])(e: =>Repr[D,S]): Repr[D,S] = If(c, t, e)
def add(lhs: Repr[Int,Int], rhs: Repr[Int,Int]): Repr[Int,Int] = Add(lhs, rhs)
def mul(lhs: Repr[Int,Int], rhs: Repr[Int,Int]): Repr[Int,Int] = Mul(lhs, rhs)
def leq(lhs: Repr[Int,Int], rhs: Repr[Int,Int]): Repr[Boolean,Boolean] = Leq(lhs, rhs)
def fix[A,B](f: (() => RLam[A,B]) => RLam[A,B]): RLam[A,B] = {
val ph = new PH
Fix(resolvePH(ph, f(() => ph)))
}
override def hole[D,S](x: =>Repr[D,S]): Repr[D,S] = Hole(x)
def eval[T](exp: Repr[T,T]): T = (reduce(exp) match {
case Cst(i) => i
case _ =>
sys.error("Wont happen. Repr of a lambda does not have right signature")
}).asInstanceOf[T]
/** big step reduction */
private def reduce(exp: Exp): Value = exp match {
case v: Value => v
case App(fun, arg) => reduce(fun) match {
case Lam(body) =>
// We do lazy eval
reduce(subst(body, arg))
case _ => stuck
}
case If(c, t, e) => reduce(c) match {
case Cst(true) => reduce(t)
case Cst(false) => reduce(e)
case _ => stuck
}
case Add(l, r) => (reduce(l), reduce(r)) match {
case (Cst(x: Int), Cst(y: Int)) => Cst(x + y)
case _ => stuck
}
case Mul(l, r) => (reduce(l), reduce(r)) match {
case (Cst(x: Int), Cst(y: Int)) => Cst(x * y)
case _ => stuck
}
case Leq(l, r) => (reduce(l), reduce(r)) match {
case (Cst(x: Int), Cst(y: Int)) => Cst(x <= y)
case _ => stuck
}
case Fix(body) =>
// Lazily replace ourselves
reduce(subst(body, exp))
case Hole(x) => reduce(x)
case Var(_) => sys.error("Unbound variable. You die!")
case _: PH => sys.error("Unbound placeholder. You die!")
}
private def stuck = sys.error("stuck. you die!")
private def resolvePH(ph: PH, e: Exp): Exp =
new VarResolveTransformer(ph).transform(e)
private def subst(body: Exp, v: Exp) =
new VarSubstTransformer(v).transform(body)
private class VarSubstTransformer(val v: Exp) extends Transformer {
override def transform(e: Exp) = e match {
case Var(i) if i == depth =>
super.transform(v)
case _ =>
super.transform(e)
}
}
private class VarResolveTransformer(ph: PH) extends Transformer {
override def transform(e: Exp) = e match {
case `ph` => Var(depth)
case _ =>
super.transform(e)
}
}
private class Transformer {
var depth = 0
protected def descend[T](body: =>T) = {
depth += 1
val res = body
depth -= 1
res
}
def transform(e: Exp): Exp = e match {
case Var(_) | Cst(_) | _ :PH => e
case Lam(f) => descend { Lam(transform(f)) }
case App(fun, body) => App(transform(fun), transform(body))
case Fix(f) => descend { Fix(transform(f)) }
case If(c,t,e) => If(transform(c), transform(t), transform(e))
case Add(lhs, rhs) => Add(transform(lhs), transform(rhs))
case Mul(lhs, rhs) => Mul(transform(lhs), transform(rhs))
case Leq(lhs, rhs) => Leq(transform(lhs), transform(rhs))
case Hole(x) => Hole(transform(x))
}
}
}