|
1 |
|
2 type Num = Int |
|
3 type Idn = String |
|
4 |
|
5 var counter = -1 |
|
6 // for generating new variables |
|
7 |
|
8 def Fresh(x: Idn) = { |
|
9 counter += 1 |
|
10 x ++ "_" ++ counter.toString() |
|
11 } |
|
12 |
|
13 def commas(s: List[String]) : String = s match { |
|
14 case Nil => "" |
|
15 case s::Nil => s |
|
16 case s::ss => s + "," + commas(ss) |
|
17 } |
|
18 def cutlines(s: List[String]) : String = s match { |
|
19 case Nil => "" |
|
20 case s::ss => s + "\n" + cutlines(ss) |
|
21 } |
|
22 |
|
23 |
|
24 abstract class Prim |
|
25 case class PLUS() extends Prim { override def toString = " + " } |
|
26 case class MINUS() extends Prim { override def toString = " - " } |
|
27 case class MULT() extends Prim { override def toString = " * " } |
|
28 |
|
29 abstract class FTerm |
|
30 case class FVar(x : Idn) extends FTerm { override def toString = x } |
|
31 case class FNum(i : Num) extends FTerm { override def toString = i.toString } |
|
32 case class FFix(x : Idn, x1: Idn, e : FTerm) extends FTerm { |
|
33 override def toString = "fix " + x + "(" + x1 + ")" + "." + e |
|
34 } |
|
35 case class FApp(e1 : FTerm, e2 : FTerm) extends FTerm { |
|
36 override def toString = "(" + e1 + ") (" + e2 + ")" |
|
37 } |
|
38 case class FTuple(es : List[FTerm]) extends FTerm { |
|
39 override def toString = "<" + commas(es.map(_.toString)) + ">" |
|
40 } |
|
41 case class FProj(i : Num, e : FTerm) extends FTerm { |
|
42 override def toString = "proj " + i.toString + " " + e |
|
43 } |
|
44 case class FPrimOp(e1 : FTerm, p : Prim, e2 : FTerm) extends FTerm { |
|
45 override def toString = e1 + p.toString + e2 |
|
46 } |
|
47 case class FIf0(e1 : FTerm, e2 : FTerm, e3 : FTerm) extends FTerm { |
|
48 override def toString = "if0(" + e1 + "," + e2 + "," + e3 + ")" |
|
49 } |
|
50 |
|
51 |
|
52 abstract class KTerm |
|
53 abstract class KVal |
|
54 |
|
55 case class KApp(v : KVal, vs : List[KVal]) extends KTerm { |
|
56 override def toString = v + "(" + commas(vs.map(_.toString)) + ")" |
|
57 } |
|
58 case class KIf0(v : KVal, e1 : KTerm, e2 : KTerm) extends KTerm { |
|
59 override def toString = "if0(" + v + "," + e1 + "," + e2 + ")" |
|
60 } |
|
61 case class KHalt(v : KVal) extends KTerm { override def toString = "halt " + v } |
|
62 case class KLet(x : Idn, v : KVal, e : KTerm) extends KTerm { |
|
63 override def toString = "let " + x + " = " + v + " in " + e |
|
64 } |
|
65 case class KLetProj(x : Idn, i : Num, v : KVal, e : KTerm) extends KTerm { |
|
66 override def toString = "let " + x + " =" + i + " " + v + " in " + e |
|
67 } |
|
68 case class KLetPrimOp(x : Idn, v1 : KVal, p : Prim, v2 : KVal, e : KTerm) extends KTerm { |
|
69 override def toString = "let " + x + " = " + v1 + p + v2 + " in " + e |
|
70 } |
|
71 |
|
72 |
|
73 case class KVVar(x : Idn) extends KVal { override def toString = x } |
|
74 case class KVNum(i : Num) extends KVal { override def toString = i.toString } |
|
75 case class KVTuple(vs : List[KVal]) extends KVal { |
|
76 override def toString = "<" + commas(vs.map(_.toString)) + ">" |
|
77 } |
|
78 case class KVFix(x : Idn, args : List[Idn], e : KTerm) extends KVal { |
|
79 override def toString = "fix " + x + "(" + commas(args) + ")." + e |
|
80 } |
|
81 |
|
82 // CPS tail translation |
|
83 def CPST(e: FTerm) : (KVal => KTerm) = e match { |
|
84 case FVar(x) => (c: KVal) => KApp(c, List(KVVar(x))) |
|
85 case FNum(i) => (c: KVal) => KApp(c, List(KVNum(i))) |
|
86 case FIf0(e1, e2, e3) => (c: KVal) => { |
|
87 val e1_prime = CPS(e1) |
|
88 val e2_prime = CPST(e2) |
|
89 val e3_prime = CPST(e3) |
|
90 e1_prime((y: KVal) => KIf0(y, e2_prime(c), e3_prime(c))) |
|
91 } |
|
92 case FPrimOp(e1, op, e2) => (c: KVal) => { |
|
93 val z = Fresh("z") |
|
94 val e1_prime = CPS(e1) |
|
95 val e2_prime = CPS(e2) |
|
96 e1_prime((y1: KVal) => |
|
97 e2_prime((y2: KVal) => |
|
98 KLetPrimOp(z, y1, op, y2, KApp(c, List(KVVar(z)))))) |
|
99 } |
|
100 case FFix(x, x1, e) => (c: KVal) => { |
|
101 val c_prime = Fresh("c'") |
|
102 val e_prime = CPST(e) |
|
103 KApp(c, List(KVFix(x, List(x1, c_prime), e_prime(KVVar(c_prime))))) |
|
104 } |
|
105 case FApp(e1, e2) => (c: KVal) => { |
|
106 val e1_prime = CPS(e1) |
|
107 val e2_prime = CPS(e2) |
|
108 e1_prime((y1: KVal) => |
|
109 e2_prime((y2: KVal) => |
|
110 KApp(y1, List(y2, c)))) |
|
111 } |
|
112 case FTuple(es) => (c: KVal) => { |
|
113 def aux(es: List[FTerm], vs: List[KVal]) : KTerm = es match { |
|
114 case Nil => KApp(c, vs.reverse) |
|
115 case (e::es) => CPS(e)((y: KVal) => aux(es, y::vs)) |
|
116 } |
|
117 aux(es, Nil) |
|
118 } |
|
119 case FProj(i, e) => (c: KVal) => { |
|
120 val z = Fresh("z") |
|
121 CPS(e)((y: KVal) => KLetProj(z, i, y, KApp(c, List(KVVar(z))))) |
|
122 } |
|
123 } |
|
124 |
|
125 // CPS translation |
|
126 def CPS(e: FTerm) : (KVal => KTerm) => KTerm = e match { |
|
127 case FVar(i) => (k: KVal => KTerm) => k(KVVar(i)) |
|
128 case FNum(i) => (k: KVal => KTerm) => k(KVNum(i)) |
|
129 case FFix(x, x1, e) => (k: KVal => KTerm) => { |
|
130 val c = Fresh("c") |
|
131 val e_prime = CPST(e) |
|
132 k(KVFix(x, List(x1, c), e_prime(KVVar(c)))) |
|
133 } |
|
134 case FApp(e1, e2) => (k: KVal => KTerm) => { |
|
135 val fr = Fresh("") |
|
136 val z = Fresh("z") |
|
137 val e1_prime = CPS(e1) |
|
138 val e2_prime = CPS(e2) |
|
139 e1_prime((y1: KVal) => |
|
140 e2_prime((y2: KVal) => |
|
141 KApp(y1, List(y2, KVFix(fr, List(z), k(KVVar(z))))))) |
|
142 } |
|
143 case FIf0(e1, e2, e3) => (k: KVal => KTerm) => { |
|
144 val fr = Fresh("") |
|
145 val c = Fresh("c") |
|
146 val z = Fresh("z") |
|
147 val e1_prime = CPS(e1) |
|
148 val e2_prime = CPST(e2) |
|
149 val e3_prime = CPST(e3) |
|
150 e1_prime((y: KVal) => |
|
151 KLet(c, KVFix(fr, List(z), k(KVVar(z))), |
|
152 KIf0(y, e2_prime(KVVar(c)), e3_prime(KVVar(c))))) |
|
153 } |
|
154 case FPrimOp(e1, op, e2) => (k: KVal => KTerm) => { |
|
155 val z = Fresh("z") |
|
156 val e1_prime = CPS(e1) |
|
157 val e2_prime = CPS(e2) |
|
158 e1_prime((y1: KVal) => e2_prime((y2: KVal) => KLetPrimOp(z, y1, op, y2, k(KVVar(z))))) |
|
159 } |
|
160 case FTuple(es) => (k: KVal => KTerm) => { |
|
161 def aux(es: List[FTerm], vs: List[KVal]) : KTerm = es match { |
|
162 case Nil => k(KVTuple(vs.reverse)) |
|
163 case (e::es) => CPS(e)((y: KVal) => aux(es, y::vs)) |
|
164 } |
|
165 aux(es, Nil) |
|
166 } |
|
167 case FProj(i, e) => (k: KVal => KTerm) => { |
|
168 val z = Fresh("z") |
|
169 CPS(e)((y: KVal) => KLetProj(z, i, y, k(KVVar(z)))) |
|
170 } |
|
171 } |
|
172 |
|
173 |
|
174 |
|
175 //free variable function |
|
176 def FVKval(v: KVal) : Set[Idn] = v match { |
|
177 case KVVar(x) => Set(x) |
|
178 case KVNum(i) => Set() |
|
179 case KVTuple(vs) => vs.flatMap{FVKval}.toSet |
|
180 case KVFix(x, args, e) => FVKexp(e) -- args - x |
|
181 } |
|
182 |
|
183 def FVKexp(e: KTerm) : Set[Idn] = e match { |
|
184 case KApp(v, vs) => FVKval(v) ++ vs.flatMap{FVKval}.toSet |
|
185 case KIf0(v, e1, e2) => FVKval(v) ++ FVKexp(e1) ++ FVKexp(e2) |
|
186 case KHalt(v) => FVKval(v) |
|
187 case KLet(x, v, e) => FVKval(v) ++ (FVKexp(e) - x) |
|
188 case KLetProj(x, i, v, e) => FVKval(v) ++ (FVKexp(e) - x) |
|
189 case KLetPrimOp(x, v1, p, v2, e) => (FVKexp(e) - x) ++ FVKval(v1) ++ FVKval(v2) |
|
190 } |
|
191 |
|
192 |
|
193 abstract class CTerm |
|
194 abstract class CVal |
|
195 |
|
196 case class CApp(v : CVal, vs : List[CVal]) extends CTerm { |
|
197 override def toString = v + "(" + commas(vs.map(_.toString)) + ")" |
|
198 } |
|
199 case class CIf0(v : CVal, e1 : CTerm, e2 : CTerm) extends CTerm { |
|
200 override def toString = "if0(" + v + "," + e1 + "," + e2 + ")" |
|
201 } |
|
202 case class CHalt(v : CVal) extends CTerm { override def toString = "halt " + v } |
|
203 case class CLet(x : Idn, v : CVal, e : CTerm) extends CTerm { |
|
204 override def toString = "let " + x + " = " + v + " in\n" + e |
|
205 } |
|
206 case class CLetProj(x : Idn, i : Num, v : CVal, e : CTerm) extends CTerm { |
|
207 override def toString = "let " + x + " =" + i + " " + v + " in\n" + e |
|
208 } |
|
209 case class CLetPrimOp(x : Idn, v1 : CVal, p : Prim, v2 : CVal, e : CTerm) extends CTerm { |
|
210 override def toString = "let " + x + " =" + v1 + p + v2 + " in\n" + e |
|
211 } |
|
212 |
|
213 case class CVVar(x : Idn) extends CVal { override def toString = x } |
|
214 case class CVNum(i : Num) extends CVal { override def toString = i.toString } |
|
215 case class CVTuple(vs : List[CVal]) extends CVal { |
|
216 override def toString = "<" + commas(vs.map(_.toString)) + ">" |
|
217 } |
|
218 case class CVFixCode(x : Idn, args : List[Idn], e : CTerm) extends CVal { |
|
219 override def toString = "fixcode " + x + "(" + commas(args) + ")." + e |
|
220 } |
|
221 |
|
222 |
|
223 |
|
224 // closure conversion |
|
225 def CExp(e: KTerm) : CTerm = e match { |
|
226 case KApp(v, vs) => { |
|
227 val z = Fresh("z") |
|
228 val z_code = Fresh("zcode") |
|
229 val z_env = Fresh("zenv") |
|
230 CLet(z, CVal(v), |
|
231 CLetProj(z_code, 0, CVVar(z), |
|
232 CLetProj(z_env, 1, CVVar(z), |
|
233 CApp(CVVar(z_code), CVVar(z_env) :: vs.map{CVal})))) |
|
234 } |
|
235 case KIf0(v, e1, e2) => CIf0(CVal(v), CExp(e1), CExp(e2)) |
|
236 case KHalt(v) => CHalt(CVal(v)) |
|
237 case KLet(x, v, e) => CLet(x, CVal(v), CExp(e)) |
|
238 case KLetProj(x, i, v, e) => CLetProj(x, i, CVal(v), CExp(e)) |
|
239 case KLetPrimOp(x, v1, p, v2, e) => CLetPrimOp(x, CVal(v1), p, CVal(v2), CExp(e)) |
|
240 } |
|
241 |
|
242 def CVal(v: KVal) : CVal = v match { |
|
243 case KVVar(x) => CVVar(x) |
|
244 case KVNum(i) => CVNum(i) |
|
245 case KVTuple(vs) => CVTuple(vs.map{CVal}) |
|
246 case KVFix(x, args, e) => { |
|
247 val x_env = Fresh(x + ".env") |
|
248 val ys = FVKval(KVFix(x, args, e)).toList |
|
249 val ys_index = |
|
250 ys.zipWithIndex.foldRight(CExp(e)) {case ((x, n), e) => CLetProj(x, n, CVVar(x_env), e) } |
|
251 val v_code = CVFixCode(x, x_env :: args, ys_index) |
|
252 val v_env = CVTuple(ys.map{CVVar(_)}) |
|
253 CVTuple(List(v_code, v_env)) |
|
254 } |
|
255 } |
|
256 |
|
257 abstract class HTerm |
|
258 abstract class HVal { |
|
259 def eval(env: Map[Idn, HVal]) : HVal |
|
260 } |
|
261 |
|
262 case class HApp(v : HVal, vs : List[HVal]) extends HTerm { |
|
263 override def toString = v + "(" + commas (vs.map(_.toString)) + ")" |
|
264 } |
|
265 case class HIf0(v : HVal, e1 : HTerm, e2 : HTerm) extends HTerm { |
|
266 override def toString = "if0(" + v + "," + e1 + "," + e2 + ")" |
|
267 } |
|
268 case class HHalt(v : HVal) extends HTerm { |
|
269 override def toString = "halt " + v |
|
270 } |
|
271 case class HLet(x : Idn, v : HVal, e : HTerm) extends HTerm { |
|
272 override def toString = "let " + x + " = " + v + " in\n" + e |
|
273 } |
|
274 case class HLetProj(x : Idn, i : Num, v : HVal, e : HTerm) extends HTerm { |
|
275 override def toString = "let " + x + " =" + i + " " + v + " in\n" + e |
|
276 } |
|
277 case class HLetPrimOp(x : Idn, v1 : HVal, p : Prim, v2 : HVal, e : HTerm) extends HTerm { |
|
278 override def toString = "let " + x + " = " + v1 + p + v2 + " in\n" + e |
|
279 } |
|
280 |
|
281 case class HVVar(x : Idn) extends HVal { |
|
282 override def toString = x |
|
283 def eval(env: Map[Idn, HVal]) : HVal = env(x) |
|
284 } |
|
285 case class HVNum(i : Num) extends HVal { |
|
286 override def toString = i.toString |
|
287 def eval(env: Map[Idn, HVal]) : HVal = HVNum(i) |
|
288 } |
|
289 case class HVTuple(vs : List[HVal]) extends HVal { |
|
290 override def toString = "<" + commas (vs.map(_.toString)) + ">" |
|
291 def eval(env: Map[Idn, HVal]) : HVal = HVTuple(vs.map(_.eval(env))) |
|
292 } |
|
293 case class HVLabel(l: Idn) extends HVal { |
|
294 override def toString = l |
|
295 def eval(env: Map[Idn, HVal]) : HVal = HVLabel(l) |
|
296 } |
|
297 |
|
298 |
|
299 case class HBlock(args: List[Idn], term: HTerm) { |
|
300 override def toString = "code(" + commas(args) + ").\n" + term + "\n" |
|
301 } |
|
302 |
|
303 case class HProg(blocks: Map[Idn, HBlock], term: HTerm) { |
|
304 override def toString = "\nheap:\n" + |
|
305 cutlines(blocks.toList.map(_ match { case (x, y) => x + " -> " + y.toString })) + |
|
306 "in start:\n" + term.toString |
|
307 |
|
308 def run_block(pretty: Boolean, l: Idn, as: List[HVal], env: Map[Idn, HVal]) : Unit = { |
|
309 val blk = blocks(l) |
|
310 val env_prime = (blk.args zip as).toMap |
|
311 if (pretty) println("Referenced: " + l + " -> " + blk) |
|
312 run(pretty, blk.term, env ++ env_prime) |
|
313 } |
|
314 |
|
315 def run(pretty: Boolean, e: HTerm, env: Map[Idn, HVal]) : Unit = { |
|
316 if (pretty) println("Env:" + env.toList.length + " stored values)\n" + |
|
317 cutlines(env.toList.sortBy {_._1}.map(_.toString))) |
|
318 if (pretty) println("Term:\n" + e.toString) |
|
319 if (pretty) Console.readLine |
|
320 e match { |
|
321 case HHalt(v) => println ("Finished with result " + v.eval(env)) |
|
322 case HApp(v, vs) => (v.eval(env), vs.map(_.eval(env))) match { |
|
323 case (HVLabel(l), vs) => run_block(pretty, l, vs, env) |
|
324 case _ => throw new IllegalArgumentException("not a label") |
|
325 } |
|
326 case HLet(x, v, e) => run(pretty, e, env + (x -> v.eval(env))) |
|
327 case HLetProj(x, i, v, e) => v.eval(env) match { |
|
328 case HVTuple(vs) => run(pretty, e, env + (x -> vs(i))) |
|
329 case _ => throw new IllegalArgumentException("not a tuple") |
|
330 } |
|
331 case HLetPrimOp(x, v1, p, v2, e) => (v1.eval(env), p, v2.eval(env)) match { |
|
332 case (HVNum(m), PLUS(), HVNum(n)) => run(pretty, e, env + (x -> HVNum(m + n))) |
|
333 case (HVNum(m), MINUS(), HVNum(n)) => run(pretty, e, env + (x -> HVNum(m - n))) |
|
334 case (HVNum(m), MULT(), HVNum(n)) => run(pretty, e, env + (x -> HVNum(m * n))) |
|
335 case _ => throw new IllegalArgumentException("not a number") |
|
336 } |
|
337 case HIf0(v, e1, e2) => v.eval(env) match { |
|
338 case HVNum(0) => run(pretty, e1, env) |
|
339 case _ => run(pretty, e2, env) |
|
340 } |
|
341 } |
|
342 } |
|
343 |
|
344 def run_prog(pretty: Boolean) = run(pretty, term, Map()) |
|
345 } |
|
346 |
|
347 |
|
348 |
|
349 // hoisting |
|
350 def H(e: CTerm, ls: Map[Idn, HVal]) : (HTerm, Map[Idn, HBlock]) = e match { |
|
351 case CApp(v, vs) => { |
|
352 val (v_prime, hs) = HV(v, ls) |
|
353 val (vs_prime, hss) = vs.map{HV(_, ls)}.unzip |
|
354 (HApp(v_prime, vs_prime), hs ++ hss.flatten) |
|
355 } |
|
356 case CIf0(v, e1, e2) => { |
|
357 val (v_prime, hs1) = HV(v, ls) |
|
358 val (e1_prime, hs2) = H(e1, ls) |
|
359 val (e2_prime, hs3) = H(e2, ls) |
|
360 (HIf0(v_prime, e1_prime, e2_prime), hs1 ++ hs2 ++ hs3) |
|
361 } |
|
362 case CHalt(v) => { |
|
363 val (v_prime, hs) = HV(v, ls) |
|
364 (HHalt(v_prime), hs) |
|
365 } |
|
366 case CLet(x, v, e) => { |
|
367 val (v_prime, hs1) = HV(v, ls) |
|
368 val (e_prime, hs2) = H(e, ls) |
|
369 (HLet(x, v_prime, e_prime), hs1 ++ hs2) |
|
370 } |
|
371 case CLetProj(x, i, v, e) => { |
|
372 val (v_prime, hs1) = HV(v, ls) |
|
373 val (e_prime, hs2) = H(e, ls) |
|
374 (HLetProj(x, i, v_prime, e_prime), hs1 ++ hs2) |
|
375 } |
|
376 case CLetPrimOp(x, v1, p, v2, e) => { |
|
377 val (v1_prime, hs1) = HV(v1, ls) |
|
378 val (v2_prime, hs2) = HV(v2, ls) |
|
379 val (e_prime, hs3) = H(e, ls) |
|
380 (HLetPrimOp(x, v1_prime, p, v2_prime, e_prime), hs1 ++ hs2 ++ hs3) |
|
381 } |
|
382 } |
|
383 |
|
384 def HV(v: CVal, ls: Map[Idn, HVal]) : (HVal, Map[Idn, HBlock]) = v match { |
|
385 case CVVar(x) => ls.get(x) match { |
|
386 case Some(v) => (v, Map()) |
|
387 case None => (HVVar(x), Map()) |
|
388 } |
|
389 case CVNum(i) => (HVNum(i), Map()) |
|
390 case CVTuple(vs) => { |
|
391 val (vs_prime, hss) = vs.map{HV(_, ls)}.unzip |
|
392 (HVTuple(vs_prime), hss.flatten.toMap) |
|
393 } |
|
394 case CVFixCode(x, args, e) => { |
|
395 val l = Fresh(x + ".block") |
|
396 val (e_prime, hs) = H(e, ls + (x -> HVTuple(List(HVLabel(l), HVVar(args.head))))) |
|
397 (HVLabel(l), hs + (l -> HBlock(args, e_prime))) |
|
398 } |
|
399 } |
|
400 |
|
401 def HP(e: CTerm) = { |
|
402 val (e_prime, hs) = H(e, Map()) |
|
403 HProg(hs, e_prime) |
|
404 } |
|
405 |
|
406 |
|
407 abstract class TALVal { |
|
408 def eval(regs: Map[Idn, TALVal]) : TALVal |
|
409 } |
|
410 abstract class TALInstr { |
|
411 def update_regs(regs: Map[Idn, TALVal]) : Map[Idn, TALVal] = regs |
|
412 } |
|
413 |
|
414 case class TALReg(r: Idn) extends TALVal { |
|
415 override def toString = r |
|
416 def eval(regs: Map[Idn, TALVal]) = regs(r).eval(regs) |
|
417 } |
|
418 case class TALLabel(l: Idn) extends TALVal { |
|
419 override def toString = l |
|
420 def eval(regs: Map[Idn, TALVal]) = TALLabel(l) |
|
421 } |
|
422 case class TALNum(i: Int) extends TALVal { |
|
423 override def toString = i.toString |
|
424 def eval(regs: Map[Idn, TALVal]) = TALNum(i) |
|
425 } |
|
426 case class TALTuple(vs: List[TALVal]) extends TALVal { |
|
427 override def toString = "<" + commas (vs.map(_.toString)) + ">" |
|
428 def eval(regs: Map[Idn, TALVal]) = TALTuple(vs.map(_.eval(regs))) |
|
429 } |
|
430 |
|
431 |
|
432 case class TALAdd(r1: Idn, r2: Idn, v: TALVal) extends TALInstr { |
|
433 override def toString = "Add " + r1 + " " + r2 + " " + v |
|
434 override def update_regs (regs: Map[Idn, TALVal]) : Map[Idn, TALVal] = (regs(r2), v) match { |
|
435 case (TALNum(n), TALNum(m)) => regs + (r1 -> TALNum(n + m)) |
|
436 case (TALNum(n), TALReg(r3)) => regs(r3) match { |
|
437 case TALNum(m) => regs + (r1 -> TALNum (n + m)) |
|
438 case _ => throw new IllegalArgumentException("not a number") |
|
439 } |
|
440 case _ => throw new IllegalArgumentException("not a number") |
|
441 } |
|
442 } |
|
443 case class TALSub(r1: Idn, r2: Idn, v: TALVal) extends TALInstr { |
|
444 override def toString = "Sub " + r1 + " " + r2 + " " + v |
|
445 override def update_regs (regs: Map[Idn, TALVal]) : Map[Idn, TALVal] = (regs(r2), v) match { |
|
446 case (TALNum(n), TALNum(m)) => regs + (r1 -> TALNum(n - m)) |
|
447 case (TALNum(n), TALReg(r3)) => regs(r3) match { |
|
448 case TALNum(m) => regs + (r1 -> TALNum (n - m)) |
|
449 case _ => throw new IllegalArgumentException("not a number") |
|
450 } |
|
451 case _ => throw new IllegalArgumentException("not a number") |
|
452 } |
|
453 } |
|
454 case class TALMul(r1: Idn, r2: Idn, v: TALVal) extends TALInstr { |
|
455 override def toString = "Mul " + r1 + " " + r2 + " " + v |
|
456 override def update_regs (regs: Map[Idn, TALVal]) : Map[Idn, TALVal] = (regs(r2), v) match { |
|
457 case (TALNum(n), TALNum(m)) => regs + (r1 -> TALNum (n * m)) |
|
458 case (TALNum(n), TALReg(r3)) => regs(r3) match { |
|
459 case TALNum(m) => regs + (r1 -> TALNum (n * m)) |
|
460 case _ => throw new IllegalArgumentException("not a number") |
|
461 } |
|
462 case _ => throw new IllegalArgumentException("not a number") |
|
463 } |
|
464 } |
|
465 case class TALBnz(r: Idn, v: TALVal) extends TALInstr { |
|
466 override def toString = "Bnz " + r + " " + v |
|
467 } |
|
468 case class TALMov(r: Idn, v: TALVal) extends TALInstr { |
|
469 override def toString = "Mov " + r + " " + v |
|
470 override def update_regs (regs: Map[Idn, TALVal]) : Map[Idn, TALVal] = v match { |
|
471 case TALReg(r1) => regs + (r -> regs(r1)) |
|
472 case _ => regs + (r -> v) |
|
473 } |
|
474 } |
|
475 case class TALProj(r1: Idn, r2: Idn, i: Num) extends TALInstr { |
|
476 override def toString = "Ldi " + r1 + " <- " + r2 + "[" + i + "]" |
|
477 override def update_regs (regs: Map[Idn, TALVal]) : Map[Idn, TALVal] = { |
|
478 regs(r2) match { |
|
479 case TALTuple(vs) => regs + (r1 -> vs(i)) |
|
480 case _ => throw new IllegalArgumentException("not a tuple: ") |
|
481 } |
|
482 } |
|
483 } |
|
484 |
|
485 case class TALJmp(v: TALVal) extends TALInstr { |
|
486 override def toString = "Jmp " + v |
|
487 } |
|
488 case class TALHalt() extends TALInstr { |
|
489 override def toString = "halt" |
|
490 } |
|
491 |
|
492 |
|
493 case class TALBlock(regs: List[Idn], cs: List[TALInstr]) { |
|
494 override def toString = "code(" + commas(regs) + ").\n" + cutlines(cs.map{_.toString}) + "\n" |
|
495 } |
|
496 |
|
497 case class TALProg(blocks: Map[Idn, TALBlock], start: List[TALInstr]) { |
|
498 override def toString = "heap:\n" + |
|
499 cutlines(blocks.toList.map(_ match { case (x, y) => x + " -> " + y.toString })) + |
|
500 "start block:\n" + cutlines(start.map(_.toString)) |
|
501 |
|
502 def run_block(pretty: Boolean, l: Idn, regs: Map[Idn, TALVal]) : Unit = { |
|
503 val blk = blocks(l) |
|
504 if (pretty) println("Referenced: " + l + " -> " + blk) |
|
505 val regs_prime = for ((r, n) <- blk.regs.zipWithIndex) yield (r, TALReg("RArg_" + n.toString).eval(regs)) |
|
506 run(pretty, blk.cs, regs ++ regs_prime.toMap) |
|
507 } |
|
508 |
|
509 def run(pretty: Boolean, cs: List[TALInstr], regs: Map[Idn, TALVal]) : Unit = { |
|
510 if (pretty) println("Regs:(" + regs.toList.length + " stored values)\n" + |
|
511 cutlines(regs.toList.sortBy {_._1}.map(_.toString))) |
|
512 if (pretty) println("Instrs:\n" + cutlines(cs.map(_.toString))) |
|
513 if (pretty) Console.readLine |
|
514 cs match { |
|
515 case (TALHalt() :: _) => println ("Finished with result " + regs("RArg_0")) |
|
516 case (TALJmp(TALLabel(l)) :: _) => run_block(pretty, l, regs) |
|
517 case (TALJmp(TALReg(r)) :: _) => regs(r) match { |
|
518 case TALLabel(l) => run_block(pretty, l, regs) |
|
519 case _ => throw new IllegalArgumentException("jump to non-label") |
|
520 } |
|
521 case (TALBnz(r, TALLabel(l)) :: cs) => regs(r) match { |
|
522 case TALNum(0) => run(pretty, cs, regs) |
|
523 case _ => run_block(pretty, l, regs) |
|
524 } |
|
525 case (c :: cs) => run(pretty, cs, c.update_regs(regs)) |
|
526 case Nil => throw new IllegalArgumentException("no instruction left") |
|
527 } |
|
528 } |
|
529 |
|
530 def run_prog(pretty: Boolean) : Unit = run(pretty, start, Map()) |
|
531 } |
|
532 |
|
533 def mk_vreg(s: String) = "Reg_" + s |
|
534 def mk_areg(i: Int) = "RArg_" + i.toString |
|
535 |
|
536 |
|
537 def Tval(v: HVal) : TALVal = v match { |
|
538 case HVVar(x) => TALReg("Reg_" + x) |
|
539 case HVNum(i) => TALNum(i) |
|
540 case HVTuple(vs) => TALTuple(vs.map(Tval)) |
|
541 case HVLabel(l) => TALLabel(l) |
|
542 } |
|
543 |
|
544 def Texp(e: HTerm) : (Map[Idn, TALBlock], List[TALInstr]) = e match { |
|
545 case HApp(v, vs) => { |
|
546 val fr_reg0 = Fresh("r0") |
|
547 val fr_regs = vs.map((v) => Fresh("r")) |
|
548 val movs0 = List(TALMov(fr_reg0, Tval(v))) |
|
549 val movs1 = for ((r, v) <- (fr_regs zip vs)) yield TALMov(r, Tval(v)) |
|
550 val movs2 = for ((r, i) <- fr_regs.zipWithIndex) yield TALMov(mk_areg(i), TALReg(r)) |
|
551 val movs3 = List(TALJmp(TALReg(fr_reg0))) |
|
552 (Map(), movs0 ::: movs1 ::: movs2 ::: movs3) |
|
553 } |
|
554 case HIf0(v, e1, e2) => { |
|
555 val l = Fresh("else_branch") |
|
556 val r = Fresh("r") |
|
557 val (h1, comp1) = Texp(e1) |
|
558 val (h2, comp2) = Texp(e2) |
|
559 val code = List(TALMov(r, Tval(v)), TALBnz(r, TALLabel(l))) |
|
560 val h3 = TALBlock(Nil, comp2) |
|
561 (h1 ++ h2 + (l -> h3), code ::: comp1) |
|
562 } |
|
563 case HHalt(v) => { |
|
564 (Map(), List(TALMov(mk_areg(0), Tval(v)), TALHalt())) |
|
565 } |
|
566 case HLet(x, v, e) => { |
|
567 val (h, comp) = Texp(e) |
|
568 val code = TALMov(mk_vreg(x), Tval(v)) |
|
569 (h, code :: comp) |
|
570 } |
|
571 case HLetPrimOp(x, v1, PLUS(), v2, e) => { |
|
572 val r = mk_vreg(x) |
|
573 val (h, comp) = Texp(e) |
|
574 val code = List(TALMov(r, Tval(v1)), TALAdd(r, r, Tval(v2))) |
|
575 (h, code ::: comp) |
|
576 } |
|
577 case HLetPrimOp(x, v1, MINUS(), v2, e) => { |
|
578 val r = mk_vreg(x) |
|
579 val (h, comp) = Texp(e) |
|
580 val code = List(TALMov(r, Tval(v1)), TALSub(r, r, Tval(v2))) |
|
581 (h, code ::: comp) |
|
582 } |
|
583 case HLetPrimOp(x, v1, MULT(), v2, e) => { |
|
584 val r = mk_vreg(x) |
|
585 val (h, comp) = Texp(e) |
|
586 val code = List(TALMov(r, Tval(v1)), TALMul(r, r, Tval(v2))) |
|
587 (h, code ::: comp) |
|
588 } |
|
589 case HLetProj(x, i, v, e) => { |
|
590 val r = mk_vreg(x) |
|
591 val (h, comp) = Texp(e) |
|
592 val code = List(TALMov(r, Tval(v)), TALProj(r, r, i)) |
|
593 (h, code ::: comp) |
|
594 } |
|
595 } |
|
596 |
|
597 def Tblock(l: Idn, hb: HBlock) : List[(Idn, TALBlock)] = hb match { |
|
598 case HBlock(args, e) => { |
|
599 val (h, comp) = Texp(e) |
|
600 (l, TALBlock(args.map("Reg_" + _), comp)) :: h.toList |
|
601 } |
|
602 } |
|
603 |
|
604 def Tprog(prog: HProg) = prog match { |
|
605 case HProg(heaps, e) => { |
|
606 val (hs, comp) = Texp(e) |
|
607 val heap_prime = for ((l, hb) <- heaps) yield Tblock(l, hb) |
|
608 TALProg(hs ++ heap_prime.flatten.toMap, comp) |
|
609 } |
|
610 } |
|
611 |
|
612 /* Simple examples |
|
613 |
|
614 // tuple <1,2,3> |
|
615 val prog0 = FTuple(List(FNum(1), FNum(2), FNum(3))) |
|
616 val Kresult0 = CPS(prog0)((y:KVal) => KHalt(y)) |
|
617 val Cresult0 = CExp(Kresult0) |
|
618 val Hresult0 = HP(Cresult0) |
|
619 val Tresult0 = Tprog(Hresult0) |
|
620 |
|
621 println("tuple example: \n") |
|
622 println("F: " + prog0.toString) |
|
623 println("K: " + Kresult0.toString) |
|
624 println("C: " + Cresult0.toString) |
|
625 println("H: " + Hresult0.toString) |
|
626 println("T: " + Tresult0.toString + "\n") |
|
627 Tresult0.run_prog(true) |
|
628 Console.readLine |
|
629 |
|
630 // tuple Proj 1 <1,2,3> |
|
631 val prog1 = FProj(1, FTuple(List(FNum(1), FNum(2), FNum(3)))) |
|
632 val Kresult1 = CPS(prog1)((y:KVal) => KHalt(y)) |
|
633 val Cresult1 = CExp(Kresult1) |
|
634 val Hresult1 = HP(Cresult1) |
|
635 val Tresult1 = Tprog(Hresult1) |
|
636 |
|
637 println("tuple - proj: \n") |
|
638 println("F: " + prog1.toString) |
|
639 println("K: " + Kresult1.toString) |
|
640 println("C: " + Cresult1.toString) |
|
641 println("H: " + Hresult1.toString) |
|
642 println("T: " + Tresult1.toString + "\n") |
|
643 Tresult1.run_prog(true) |
|
644 Console.readLine |
|
645 |
|
646 // 3 + 4 |
|
647 val prog2 = FPrimOp(FNum(3),PLUS(),FNum(4)) |
|
648 val Kresult2 = CPS(prog2)((y:KVal) => KHalt(y)) |
|
649 val Cresult2 = CExp(Kresult2) |
|
650 val Hresult2 = HP(Cresult2) |
|
651 val Tresult2 = Tprog(Hresult2) |
|
652 |
|
653 println("3 + 4: \n") |
|
654 println("F: " + prog2.toString) |
|
655 println("K: " + Kresult2.toString) |
|
656 println("C: " + Cresult2.toString) |
|
657 println("H: " + Hresult2.toString) |
|
658 println("T: " + Tresult2.toString + "\n") |
|
659 Tresult2.run_prog(true) |
|
660 Console.readLine |
|
661 |
|
662 // (fix f(x). 18 * x + 32) 24 |
|
663 val d1 = FPrimOp(FPrimOp(FNum(18), MULT(), FVar("x")), PLUS(), FNum(32)) |
|
664 val prog3 = FApp(FFix("f", "x", d1), FNum(24)) |
|
665 val Kresult3 = CPS(prog3)((y:KVal) => KHalt(y)) |
|
666 val Cresult3 = CExp(Kresult3) |
|
667 val Hresult3 = HP(Cresult3) |
|
668 val Tresult3 = Tprog(Hresult3) |
|
669 |
|
670 println("(fix f(x). 18 * x + 32) 24 \n") |
|
671 println("F: " + prog3.toString + "\n") |
|
672 println("K: " + Kresult3.toString + "\n") |
|
673 println("C: " + Cresult3.toString + "\n") |
|
674 println("H: " + Hresult3.toString + "\n") |
|
675 Hresult3.run_prog(true) |
|
676 Console.readLine |
|
677 println("T: " + Tresult3.toString + "\n") |
|
678 Tresult3.run_prog(true) |
|
679 Console.readLine |
|
680 */ |
|
681 |
|
682 |
|
683 /* |
|
684 // twice-apply example |
|
685 // fix twice(f)._(x). f (f x) |
|
686 val fun = FFix("id", "x", FPrimOp(FVar("x"), MULT(), FVar("x"))) |
|
687 val ffx = FApp(FVar("f"), FApp(FVar("f"), FVar("x"))) |
|
688 val f1 = FFix("twice", "f", FFix("twicef", "x", ffx)) |
|
689 val prog4 = FApp(FApp(f1, fun), FNum(2)) |
|
690 val Kresult4 = CPS(prog4)((y:KVal) => KHalt(y)) |
|
691 val Cresult4 = CExp(Kresult4) |
|
692 val Hresult4 = HP(Cresult4) |
|
693 val Tresult4 = Tprog(Hresult4) |
|
694 |
|
695 println("twice fun 2\n") |
|
696 println("F: " + prog4.toString + "\n") |
|
697 println("K: " + Kresult4.toString + "\n") |
|
698 println("C: " + Cresult4.toString + "\n") |
|
699 println("H: " + Hresult4.toString + "\n") |
|
700 //Hresult4.run_prog(false) |
|
701 //Console.readLine |
|
702 println("T: " + Tresult4.toString + "\n") |
|
703 Tresult4.run_prog(false) |
|
704 Console.readLine |
|
705 */ |
|
706 |
|
707 /* |
|
708 //identity function |
|
709 //fix id(x). x |
|
710 val id = FFix("id", "x", FVar("x")) |
|
711 val id_three = FApp(id, FNum(3)) |
|
712 |
|
713 val Kresult5 = CPS(id_three)((y:KVal) => KHalt(y)) |
|
714 val Cresult5 = CExp(Kresult5) |
|
715 val Hresult5 = HP(Cresult5) |
|
716 val Tresult5 = Tprog(Hresult5) |
|
717 |
|
718 println("id 3:") |
|
719 println("F: " + id_three.toString) |
|
720 println("K: " + Kresult5.toString + "\n") |
|
721 println("C: " + Cresult5.toString + "\n") |
|
722 println("H: " + Hresult5.toString + "\n") |
|
723 println("T: " + Tresult5.toString + "\n") |
|
724 Tresult5.run_prog(false) |
|
725 Console.readLine |
|
726 */ |
|
727 |
|
728 /* |
|
729 //example: factorial |
|
730 val f = FVar("f") |
|
731 val n = FVar("n") |
|
732 val one = FNum(1) |
|
733 val six = FNum(15) |
|
734 val e0 = FPrimOp(n, MINUS(), one) |
|
735 val e1 = FApp(f, e0) |
|
736 val e2 = FPrimOp(n, MULT(), e1) |
|
737 val fact: FTerm = FFix("f", "n", FIf0(n, one, e2)) |
|
738 val fact_six = FApp(fact, six) |
|
739 |
|
740 |
|
741 val Kresult6 = CPS(fact_six)((y:KVal) => KHalt(y)) |
|
742 val Cresult6 = CExp(Kresult6) |
|
743 val Hresult6 = HP(Cresult6) |
|
744 val Tresult6 = Tprog(Hresult6) |
|
745 |
|
746 println("fact 6: \n") |
|
747 println("F: " + fact_six) |
|
748 Console.readLine |
|
749 println("K: " + Kresult6.toString + "\n") |
|
750 Console.readLine |
|
751 println("C: " + Cresult6.toString + "\n") |
|
752 Console.readLine |
|
753 println("H: " + Hresult6.toString + "\n") |
|
754 println("-----------------------------") |
|
755 println("Execution") |
|
756 Hresult6.run_prog(false) |
|
757 Console.readLine |
|
758 println("T: " + Tresult6.toString + "\n") |
|
759 println("-----------------------------") |
|
760 println("Execution") |
|
761 Tresult6.run_prog(false) |
|
762 Console.readLine |
|
763 */ |
|
764 |
|
765 |
|
766 //example: fibonacci |
|
767 // fib(n).if0(n, 1,if0(n - 1, 1, fib(n - 1) + fib(n - 2))) |
|
768 val fib = FVar("fib") |
|
769 val n = FVar("n") |
|
770 val one = FNum(1) |
|
771 val two = FNum(2) |
|
772 val minus_one = FPrimOp(n, MINUS(), one) |
|
773 val minus_two = FPrimOp(n, MINUS(), two) |
|
774 val fibonacci = |
|
775 FFix("fib", "n", |
|
776 FIf0(n, one, |
|
777 FIf0(minus_one, one, FPrimOp(FApp(fib, minus_one), PLUS(), FApp(fib, minus_two))))) |
|
778 val fib_apply = FApp(fibonacci, FNum(4)) |
|
779 |
|
780 val Kresult7 = CPS(fib_apply)((y:KVal) => KHalt(y)) |
|
781 val Cresult7 = CExp(Kresult7) |
|
782 val Hresult7 = HP(Cresult7) |
|
783 val Tresult7 = Tprog(Hresult7) |
|
784 |
|
785 println("fib: \n") |
|
786 println("F: " + fib_apply) |
|
787 Console.readLine |
|
788 println("K: " + Kresult7.toString + "\n") |
|
789 Console.readLine |
|
790 println("C: " + Cresult7.toString + "\n") |
|
791 Console.readLine |
|
792 println("H: " + Hresult7.toString + "\n") |
|
793 println("-----------------------------") |
|
794 println("H Prog") |
|
795 Hresult7.run_prog(false) |
|
796 Console.readLine |
|
797 println("T: " + Tresult7.toString + "\n") |
|
798 println("-----------------------------") |
|
799 println("TAL") |
|
800 Tresult7.run_prog(false) |
|
801 Console.readLine |