-
Notifications
You must be signed in to change notification settings - Fork 2
/
interp-cps.rkt
111 lines (94 loc) · 3.25 KB
/
interp-cps.rkt
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
#lang racket
(require rackunit)
(require "share.rkt")
;; Expressions
(struct NumE (n) #:transparent)
(struct IdE (id) #:transparent)
(struct PlusE (l r) #:transparent)
(struct MultE (l r) #:transparent)
(struct AppE (fun arg) #:transparent)
(struct LamE (arg body) #:transparent)
(struct CallccE (k body) #:transparent)
;; Values
(struct NumV (n) #:transparent)
(struct ClosureV (arg body env) #:transparent)
(struct Cont (body))
;; Environment
(struct Binding (name val) #:transparent)
(define lookup (make-lookup 'lookup Binding? Binding-name Binding-val))
(define ext-env cons)
;; Parser
(define (parse s)
(match s
[(? number? x) (NumE x)]
[(? symbol? x) (IdE x)]
[`(+ ,l ,r) (PlusE (parse l) (parse r))]
[`(* ,l ,r) (MultE (parse l) (parse r))]
[`(λ (,var) ,body) (LamE var (parse body))]
[`(call/cc (λ (,k) ,body))
(CallccE k (parse body))]
[`(let/cc ,k ,body)
(CallccE k (parse body))]
[`(,fun ,arg) (AppE (parse fun) (parse arg))]
[else (error 'parse "invalid expression")]))
;; Interpreter
(define (primop op l r)
(match* (l r)
[((NumV lv) (NumV rv))
(match op
['+ (NumV (+ lv rv))]
['* (NumV (* lv rv))])]
[(_ _) (error 'primop "invalid operator")]))
(define (interp-cps exp env k)
(match exp
[(IdE x) (k (lookup x env))]
[(NumE n) (k (NumV n))]
[(PlusE l r)
(interp-cps l env
(λ (lv)
(interp-cps r env
(λ (rv)
(k (primop '+ lv rv))))))]
[(MultE l r)
(interp-cps l env
(λ (lv)
(interp-cps r env
(λ (rv)
(k (primop '* lv rv))))))]
[(LamE arg body)
(k (ClosureV arg body env))]
[(CallccE x body)
(interp-cps body (ext-env (Binding x (Cont k)) env) k)]
[(AppE fun arg)
(interp-cps fun env
(λ (funv)
(cond [(ClosureV? funv)
(interp-cps arg env
(λ (argv)
(interp-cps (ClosureV-body funv)
(ext-env (Binding (ClosureV-arg funv) argv)
(ClosureV-env funv))
k)))]
[(Cont? funv) (interp-cps arg env (Cont-body funv))]
[else (error 'cps "not a function or continuation")])))]))
(define mt-env empty)
(define mt-k (lambda (v) v))
(define (run prog)
(define prog* (parse prog))
(interp-cps prog* mt-env mt-k))
;; Tests
(check-equal? (run '{+ 1 2}) (NumV 3))
(check-equal? (run '{* 2 3}) (NumV 6))
(check-equal? (run '{{λ {x} {+ x x}} 3})
(NumV 6))
(check-equal? (run '{+ 1 {let/cc k1
{+ 2 {+ 3 {let/cc k2
{+ 4 {k1 5}}}}}}})
(NumV 6))
(check-equal? (run '{+ 1 {let/cc k1
{+ 2 {+ 3 {let/cc k2
{+ 4 {k2 5}}}}}}})
(NumV 11))
(check-equal? (run '{+ 1 {call/cc {λ {k1}
{+ 2 {+ 3 {k1 4}}}}}})
(NumV 5))