├── code
├── init-store-env.rkt
├── primitives.rkt
├── top.rkt
├── run.rkt
├── semantic-domains.rkt
├── env.rkt
├── parser.rkt
├── ast.rkt
├── store-list.rkt
└── eval-ast.rkt
├── readme
├── readme~
└── tests
└── tests.rkt
/code/init-store-env.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 |
4 | (provide
5 | make-init-store-env
6 | *init-store-env*
7 | *init-env*
8 | *init-store*)
9 |
10 | ;;; ===================
11 | ;;; Initial Environment
12 | ;;; ===================
13 |
14 | (require "primitives.rkt")
15 | (require "store-list.rkt")
16 | (require "env.rkt")
17 |
18 | ;;; [(listof id?) (listof storable-value?) -> (list store? env?)
19 | (define make-init-store-env
20 | (lambda (ids vals)
21 | (let-values ([(store refs) (new-refs (new-store) vals)])
22 | (let ([env (extended-env
23 | ids refs (empty-env))])
24 | (list store env)))))
25 |
26 |
27 | ;;; (list store? env?)
28 | (define *init-store-env*
29 | (make-init-store-env
30 | '(+ - * / < <= eq? 0?)
31 | (list +p -p *p /p
::= |
12 | ;;; |
13 | ;;; |
14 | ;;; |
15 | ;;; |
16 | ;;; |
17 | ;;; |
18 | ;;; |
19 |
20 | ;;; |
21 | ;;;
22 |
23 | ;;; ::= (number )
24 | ;;; ::= (boolean )
25 | ;;; ::= (function ( ... ) )
26 | ;;; ::= (app ...)
27 | ;;; ::= (assume ( ...) )
28 | ;;; ::= ( )
29 | ;;; ::= (id-ref )
30 | ;;; ::=
31 | ;;; ::= (ifte )
32 | ;;; ::= (assume-rec ( ...) )
33 |
34 | ;;; ::= (set )
35 | ;;; ::= (seq ...)
36 |
37 |
38 |
--------------------------------------------------------------------------------
/readme~:
--------------------------------------------------------------------------------
1 | Implemention of continuation passing interpreter for a call by value language
2 |
3 |
4 | ;;; ==================================================================
5 | ;;; Abstract Syntax for the STORE-PASSING/IMPLICIT ALLOCATION language
6 | ;;; ==================================================================
7 |
8 |
9 |
10 | ;;; ::= |
11 | ;;; |
12 | ;;; |
13 | ;;; |
14 | ;;; |
15 | ;;; |
16 | ;;; |
17 | ;;; |
18 |
19 | ;;; |
20 | ;;; |
21 | ;;; |
22 | ;;; |
23 | ;;;
24 |
25 | ;;; ::= (number )
26 | ;;; ::= (boolean )
27 | ;;; ::= (function ( ... ) )
28 | ;;; ::= (app ...)
29 | ;;; ::= (assume ( ...) )
30 | ;;; ::= ( )
31 | ;;; ::= (id-ref )
32 | ;;; ::=
33 | ;;; ::= (ifte )
34 | ;;; ::= (recursive ( ...) )
35 |
36 | ;;; ::= (abort )
37 | ;;; ::= (break )
38 | ;;; ::= (try )
39 | ;;; ::= (throw )
40 | ;;; ::= (letcc )
41 |
42 |
--------------------------------------------------------------------------------
/code/top.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 | ;;; ================================
4 | ;;; Top-level setup for the language
5 | ;;; ================================
6 |
7 | (require "run.rkt")
8 | (require "parser.rkt")
9 |
10 | (provide
11 | go)
12 |
13 | (define go
14 | (lambda (e)
15 | (run (parse e))))
16 |
17 | ;;; Unit testing
18 | ;;; ============
19 | (require rackunit)
20 |
21 |
22 | (check-equal?
23 | (go '(assume-rec ([f (function (n) (ifte (0? n) 1 (* n (f (- n 1)))))])
24 | (f 3)))
25 | 6
26 | "go-factorial")
27 |
28 |
29 |
30 | (check-equal?
31 | (go
32 | '(assume-rec ([even? (function (n) (ifte (0? n) #t (odd? (- n 1))))]
33 | [odd? (function (n) (ifte (0? n) #f (even? (- n 1))))])
34 | (even? 3)))
35 | #f
36 | "go-even")
37 |
38 |
39 |
40 | (check-equal?
41 | (go
42 | '(assume ([! (function (n)
43 | (assume ([ans 1]
44 | [i n])
45 | (assume-rec ([loop (function ()
46 | (ifte
47 | (eq? i 0)
48 | ans
49 | (seq
50 | (set ans (* ans i))
51 | (set i (- i 1))
52 | (loop))))])
53 | (loop))))])
54 | (! 3)))
55 | 6
56 | "go-factorial-imperative")
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/tests/tests.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 | (require "ast.rkt")
3 | (require "init-store-env.rkt")
4 | (require "semantic-domains.rkt")
5 | (require "eval-ast.rkt")
6 | (require "top.rkt")
7 | (require "run.rkt")
8 | (require rackunit)
9 | (check-equal? (go '(assume-rec ([fact (function (n) (ifte (0? n) 1 (* n (fact (- n 1)))))])
10 | (fact 4))) 24 "first testCase")
11 |
12 | (check-equal? (go '(assume-rec ([fibo (function (n) (ifte (< n 2) 1 (+ (fibo (- n 1)) (fibo (- n 2)))))])
13 | (fibo 3))) 3 "second testCase")
14 |
15 | (check-equal? (go '(assume-rec ([f (function (n) (ifte (0? n) 1 (* n (f (- n 1)))))]
16 | [fib (function (n) (ifte (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))]
17 | [addfactfib (function (n) (+ (f n) (fib n)))])
18 | (addfactfib 3))) 9 "third testcase" )
19 |
20 | (check-equal? (go '(assume ([fib (function (n) (* n n))])
21 | (assume ([fib (function (n) (ifte (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))])
22 | (fib 3)))) 5 "fourth testcase")
23 |
24 | (check-equal? (go '(assume ([fib (function (n) (* n n))])
25 | (assume-rec ([fib (function (n) (ifte (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))])
26 | (fib 8)))) 34 "fifth testcase" )
27 |
28 |
29 | (check-equal?
30 | (run
31 | (assume-rec
32 | (list
33 | (make-bind 'even?
34 | (function '(n)
35 | (ifte (app (id-ref '0?) (list (id-ref 'n)))
36 | (boolean #t)
37 | (app (id-ref 'odd?)
38 | (list (app (id-ref '-) (list (id-ref 'n) (number 1))))))
39 | ))
40 |
41 | (make-bind 'odd?
42 | (function '(n)
43 | (ifte (app (id-ref '0?) (list (id-ref 'n)))
44 | (boolean #f)
45 | (app (id-ref 'even?)
46 | (list (app (id-ref '-) (list (id-ref 'n) (number 1))))))
47 | )))
48 | (app (id-ref 'even?) (list (number 3)))))
49 | #f
50 | "recursive-ast test")
--------------------------------------------------------------------------------
/code/run.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 | ;;; ========================================
4 | ;;; Run expression in init-env and new-store
5 | ;;; ========================================
6 |
7 | (provide
8 | run)
9 |
10 | (require "ast.rkt")
11 | (require "init-store-env.rkt")
12 | (require "semantic-domains.rkt")
13 | (require "eval-ast.rkt")
14 |
15 | ;;; run: ast? -> expressible-value?
16 | (define run
17 | (lambda (ast)
18 | (let-values ([(store val) (eval-ast ast *init-env* *init-store*)])
19 | val)))
20 |
21 | ;;; Unit testing
22 | ;;; ============
23 |
24 | (require rackunit)
25 |
26 | ;; (run (id-ref '0?))
27 |
28 |
29 |
30 | (check-equal?
31 | (run
32 | (assume (list (make-bind 'a (number 5))
33 | (make-bind 'b (number 6)))
34 | (app (id-ref '+)
35 | (list (id-ref 'a) (id-ref 'b)))))
36 | 11 "run: assume-test")
37 |
38 |
39 | (check-equal?
40 | (run
41 | (function ; (function (x y z) (+ x (* y z)))
42 | '(x y z)
43 | (app (id-ref '+)
44 | (list (id-ref 'x)
45 | (app (id-ref '*)
46 | (list (id-ref 'y) (id-ref 'z)))))))
47 | (closure '(x y z)
48 | (app (id-ref '+)
49 | (list (id-ref 'x)
50 | (app (id-ref '*)
51 | (list (id-ref 'y) (id-ref 'z)))))
52 | *init-env*)
53 | "run: function-test")
54 |
55 |
56 | ;;; (assume-rec ([even? (n) (if (0? n) #t (odd? (- n 1)))]
57 | ;;; [odd? (n) (if (0? n) #f (even? (- n 1)))])
58 | ;;; (even? 3))
59 |
60 | (check-equal?
61 | (run
62 | (assume-rec
63 | (list
64 | (make-bind 'even?
65 | (function '(n)
66 | (ifte (app (id-ref '0?) (list (id-ref 'n)))
67 | (boolean #t)
68 | (app (id-ref 'odd?)
69 | (list (app (id-ref '-)
70 | (list (id-ref 'n) (number 1))))))))
71 |
72 | (make-bind 'odd?
73 | (function '(n)
74 | (ifte (app (id-ref '0?) (list (id-ref 'n)))
75 | (boolean #f)
76 | (app (id-ref 'even?)
77 | (list (app (id-ref '-) (list (id-ref 'n) (number 1)))))))))
78 |
79 | (app (id-ref 'even?) (list (number 3)))))
80 | #f
81 | "run-assume-rec-test")
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/code/semantic-domains.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 | ;;; =================================
4 | ;;; Semantic Domains and Environments
5 | ;;; =================================
6 |
7 | (provide
8 | expressible-value?
9 | denotable-value?
10 | proc
11 | prim-proc
12 | closure
13 | proc?
14 | prim-proc?
15 | closure?
16 | rec-closure
17 | rec-closure?
18 | )
19 |
20 | (require "env.rkt")
21 |
22 | ;;; Expressible Values (types of values returned by
23 | ;;; evaluating an ast)
24 |
25 | ;;; ========================================
26 |
27 | ;;; expressible-value ::=
28 | ;;; number | boolean | proc
29 |
30 | ;;; Denotable Values (types of values denoted by
31 | ;;; identifiers)
32 | ;;; ============================================
33 |
34 | ;;; denotable-value ::= Ref(expressible-value)
35 | ;;;
36 |
37 | ;;; expressible-value? is the set of things that are the
38 | ;;; results of evaluation of expressions (asts).
39 |
40 |
41 | (require eopl/eopl)
42 | (require "ast.rkt")
43 | (require (prefix-in store: "store-list.rkt"))
44 | (require "store-list.rkt")
45 | ;;; Procedure ADT
46 | ;;; ==============
47 |
48 | (define-datatype proc proc?
49 | [prim-proc (prim procedure?)
50 | (sig (list-of procedure?))]
51 | [closure
52 | (formals (list-of symbol?))
53 | (body ast?)
54 | (env env?)]
55 | [rec-closure
56 | (formals (list-of symbol?))
57 | (body ast?)])
58 |
59 |
60 |
61 | ;;; Subtype Predicates
62 | ;;; ==================
63 |
64 | ;;; prim-proc? : proc? -> boolean?
65 | (define prim-proc?
66 | (lambda (p)
67 | (cases proc p
68 | [prim-proc (prim sig) #t]
69 | [else #f])))
70 |
71 |
72 |
73 | ;;; closure? : proc? -> boolean?
74 | (define closure?
75 | (lambda (p)
76 | (cases proc p
77 | [closure (formal body env) #t]
78 | [else #f])))
79 |
80 |
81 | ;;; rec-closure? : proc? -> boolean?
82 | (define rec-closure?
83 | (lambda (p)
84 | (cases proc p
85 | [rec-closure (formals body) #t]
86 | [else #f])))
87 |
88 |
89 | ;;; expressible-value? : any/c -> boolean?
90 | (define expressible-value?
91 | (lambda(ex)
92 | (or (number? ex)
93 | (boolean? ex)
94 | (proc? ex))))
95 |
96 | ;;; denotable-value? :any/c -> boolean?
97 | (define denotable-value?
98 | (lambda(ex)
99 | (ref? ex)))
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/code/env.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 | ;;; =================================
4 | ;;; Semantic Domains and Environments
5 | ;;; =================================
6 |
7 | (provide
8 | env
9 | env?
10 | empty-env
11 | extended-env
12 | lookup-env
13 | )
14 |
15 |
16 | ;;; Expressible Values (types of values returned by
17 | ;;; evaluating an ast)
18 |
19 |
20 | (require eopl/eopl)
21 | (require (only-in "store-list.rkt" [ref? store:ref?]))
22 | (define-datatype env env?
23 | [empty-env]
24 | [extended-env
25 | (syms (list-of symbol?))
26 | (vals (list-of store:ref?))
27 | (outer-env env?)])
28 |
29 | ;;; Subtype Predicates
30 | ;;; ==================
31 |
32 | ;;; empty-env? : env? -> boolean?
33 | (define empty-env?
34 | (lambda (e)
35 | (cases env e
36 | [empty-env () #t]
37 | [else #f])))
38 |
39 | ;;; extended-env? : env? -> boolean?
40 | (define extended-env?
41 | (lambda (e)
42 | (cases env e
43 | [extended-env (syms vals outer-env) #t]
44 | [else #f])))
45 |
46 | ;;; Returns the loction of the element in a list, -1 if the
47 | ;;; element is absent.
48 |
49 | ;;; list-index : [(listof any/c) any/c] ->
50 | (define list-index
51 | (lambda (ls a)
52 | (letrec ([loop
53 | (lambda (ls ans)
54 | (cond
55 | [(null? ls) -1]
56 | [(eq? (first ls) a) ans]
57 | [#t (loop (rest ls) (+ 1 ans))]))])
58 | (loop ls 0))))
59 |
60 | ;;; lookup-env: [env? symbol?] -> any/c
61 | ;;; lookup-env: throws "unbound identifier" error
62 | (define lookup-env
63 | (lambda (e x)
64 | (cases env e
65 | [empty-env ()
66 | (error
67 | 'lookup-env
68 | "unbound identifier ~a" x)]
69 | [extended-env (syms vals outer-env)
70 | (let ([j (list-index syms x)])
71 | (cond
72 | [(= j -1) (lookup-env outer-env x)]
73 | [#t (list-ref vals j)]))])))
74 |
75 |
76 | ;;; Unit testing
77 | ;;; ============
78 | (require rackunit)
79 |
80 | (check-pred env? (empty-env) "env?-empty-env")
81 | (check-pred empty-env? (empty-env) "empty-env?-empty-env")
82 | (check-exn exn? (lambda () (lookup-env (empty-env) 'a)) "lookup-empty-env-a")
83 |
84 | (define e1
85 | (extended-env '(x y z) '(1 2 3) (empty-env)))
86 |
87 | (check-pred env? e1 "env?-extended-env")
88 | (check-pred extended-env? e1 "extended-env?-extended-env")
89 |
90 | (check-equal? 1 (lookup-env e1 'x) "lookup-e1-x")
91 | (check-equal? 2 (lookup-env e1 'y) "lookup-e1-y")
92 | (check-exn exn? (lambda () (lookup-env e1 'a)) "lookup-e1-a")
93 |
94 | (define e2
95 | (extended-env '(w x) '(5 6) e1))
96 |
97 | (check-equal? 5 (lookup-env e2 'w) "lookup-e2-w")
98 | (check-equal? 6 (lookup-env e2 'x) "lookup-e2-x")
99 | (check-equal? 2 (lookup-env e2 'y) "lookup-e2-y")
100 | (check-equal? 3 (lookup-env e2 'z) "lookup-e2-z")
101 | (check-exn exn? (lambda () (lookup-env e2 'a)) "lookup-e2-a")
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/code/parser.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 | ;;; =================================
4 | ;;; Parser for the RECURSION language
5 | ;;; =================================
6 |
7 | ;;; Concrete Syntax
8 |
9 | ;;; := |
10 | ;;;
11 | ;;; |
12 | ;;; (ifte ) |
13 | ;;; (function ( ...) ] ...) ) |
15 | ;;; (assume-rec ([ ] ...) ) |
16 | ;;; (set ) |
17 | ;;; (seq ...) |
18 | ;;; ( ...)
19 |
20 | ;;; example concrete syntax
21 |
22 | ;;; (assume-rec ([even? (function (n) (if (0? n) #t (odd? (sub1 n))))]
23 | ;;; [odd? (function (n) (if (0? n) #f (even? (sub1 n))))])
24 | ;;; (even? 5))
25 |
26 | (require racket/match)
27 |
28 | (require "ast.rkt")
29 |
30 | (provide
31 | parse)
32 |
33 | (define *keywords*
34 | '(ifte function assume assume-rec seq set))
35 |
36 | (define id?
37 | (lambda (x)
38 | (and
39 | (symbol? x)
40 | (not (memq x *keywords*)))))
41 |
42 |
43 | (define parse
44 | (lambda (d)
45 | (match d
46 | [(? number? n) (number n)]
47 | [(? boolean? b) (boolean b)]
48 | [(? id? x) (id-ref x)]
49 | [(list 'ifte a b c) (ifte (parse a) (parse b) (parse c))]
50 |
51 | [(list
52 | 'function
53 | (list (? id? x) ...)
54 | body)
55 | (function x (parse body))]
56 |
57 | [(list 'assume
58 | (list (list (? id? x) e) ...) body)
59 | (let* ([a (map parse e)]
60 | [b (map make-bind x a)])
61 | (assume b (parse body)))]
62 |
63 | [(list 'assume-rec
64 | (list (list (? id? x) e) ...) body)
65 | (let* ([a (map parse e)]
66 | [b (map make-bind x a)])
67 | (assume-rec b (parse body)))]
68 |
69 | [(list 'set (? id? x) e)
70 | (set x (parse e))]
71 |
72 | [(list 'seq stmts ...)
73 | (seq (map parse stmts))]
74 |
75 | [(list rator rands ...)
76 | (let* ([rator (parse rator)]
77 | [rands (map parse rands)])
78 | (app rator rands))]
79 | [_ (error 'parse "don't know how to parse ~a" d)])))
80 |
81 |
82 |
83 | ;;; Unit Testing
84 | ;;; ============
85 | (require rackunit)
86 |
87 |
88 | (check-equal? (parse 4) (number 4) "parse-number")
89 | (check-equal? (parse #t) (boolean #t) "parse-boolean")
90 | (check-equal? (parse 'x) (id-ref 'x) "parse-id")
91 |
92 | (check-equal?
93 | (parse '(ifte 3 4 8))
94 | (ifte (number 3) (number 4) (number 8))
95 | "parse-ifte")
96 |
97 |
98 | (check-equal?
99 | (parse '(function (x y) 4))
100 | (function '(x y) (number 4))
101 | "parse-function")
102 |
103 |
104 | (check-equal?
105 | (parse '(assume ([x 3]) 6))
106 | (assume (list (make-bind 'x (number 3))) (number 6))
107 | "parse-assume")
108 |
109 |
110 | (check-equal?
111 | (parse '(assume-rec ([f (function (x y) x)]
112 | [g (function (m n) 5)])
113 | 9))
114 | (assume-rec
115 | (list
116 | (make-bind 'f (function '(x y) (id-ref 'x)))
117 | (make-bind 'g (function '(m n) (number 5))))
118 | (number 9))
119 | "parse-assume-rec")
120 |
121 |
122 | (check-equal?
123 | (parse '(assume-rec () 9))
124 | (assume-rec
125 | (list)
126 | (number 9))
127 | "parse-empty-assume-rec")
128 |
129 | (check-equal?
130 | (parse '(x y))
131 | (app (id-ref 'x)
132 | (list (id-ref 'y)))
133 | "parse-app")
134 |
135 | (check-equal?
136 | (parse '(set x 5))
137 | (set 'x (number 5))
138 | "parse-set")
139 |
140 | (check-equal?
141 | (parse '(seq (set x 5) x))
142 | (seq (list (set 'x (number 5)) (id-ref 'x)))
143 | "parse-seq")
144 |
145 |
146 | (check-exn exn? (lambda () (parse "hello")) "parse-string-error")
147 | (check-exn exn? (lambda () (parse '#(1 2))) "parse-vector-error")
148 | (check-exn exn? (lambda () (parse '(1 . 2)) "parse-cons-error"))
149 | (check-exn exn? (lambda () (parse '()) "parse-empty-error"))
150 | (check-exn exn? (lambda () (parse '(set 4 5))) "parse-set-error")
151 |
152 |
153 |
--------------------------------------------------------------------------------
/code/ast.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 | ;;; ==================================================================
4 | ;;; Abstract Syntax for the STORE-PASSING/IMPLICIT ALLOCATION language
5 | ;;; ==================================================================
6 |
7 |
8 |
9 | ;;; ::= |
10 | ;;; |
11 | ;;; |
12 | ;;; |
13 | ;;; |
14 | ;;; |
15 | ;;; |
16 | ;;; |
17 |
18 | ;;; |
19 | ;;;
20 |
21 | ;;; ::= (number )
22 | ;;; ::= (boolean )
23 | ;;; ::= (function ( ... ) )
24 | ;;; ::= (app ...)
25 | ;;; ::= (assume ( ...) )
26 | ;;; ::= ( )
27 | ;;; ::= (id-ref )
28 | ;;; ::=
29 | ;;; ::= (ifte )
30 | ;;; ::= (assume-rec ( ...) )
31 |
32 | ;;; ::= (set )
33 | ;;; ::= (seq ...)
34 |
35 |
36 | (require eopl/eopl)
37 |
38 | (provide
39 | ast
40 | ast?
41 | number
42 | boolean
43 | id-ref
44 | ifte
45 | assume
46 | assume-rec
47 | make-bind
48 | bind-id
49 | bind-ast
50 | function
51 | app
52 | set
53 | seq
54 | )
55 |
56 | (define-datatype ast ast?
57 | [number (datum number?)]
58 | [boolean (datum boolean?)]
59 | [id-ref (sym id?)]
60 | [ifte (test ast?) (then ast?) (else-ast ast?)]
61 | [assume (binds (list-of bind?)) (body ast?)]
62 | [assume-rec (binds (list-of bind?)) (body ast?)]
63 | [function (formals (list-of id?)) (body ast?)]
64 | [app (rator ast?) (rands (list-of ast?))]
65 | [set (lhs id?) (rhs ast?)]
66 | [seq (stmts (list-of ast?))])
67 |
68 | (define-datatype bind bind?
69 | [make-bind (b-id id?) (b-ast ast?)])
70 |
71 | ;;; bind-id : bind? -> id?
72 | (define bind-id
73 | (lambda (b)
74 | (cases bind b
75 | [make-bind (b-id b-ast) b-id])))
76 |
77 | ;;; bind-ast : bind? -> ast?
78 | (define bind-ast
79 | (lambda (b)
80 | (cases bind b
81 | [make-bind (b-id b-ast) b-ast])))
82 |
83 | (define-datatype fbind fbind?
84 | [make-fbind (fb-id id?)
85 | (fb-formals (list-of id?))
86 | (fb-body ast?)])
87 |
88 | (define id? symbol?)
89 |
90 | ;;; unit Testing
91 | ;;; ============
92 |
93 | ;;; Racket's unit testing framework
94 | (require rackunit)
95 |
96 |
97 | (define-simple-check
98 | (check-ast? thing)
99 | (ast? thing))
100 |
101 | (check-ast? (number 5) "number-5 test")
102 | (check-ast? (boolean #t) "boolean-#t test")
103 | (check-ast? (id-ref 'x) "id-ref-x test")
104 | (check-ast? (function
105 | '(x y z)
106 | (app (id-ref '+)
107 | (list (id-ref 'x)
108 | (app (id-ref '*)
109 | (list (id-ref 'y) (id-ref 'z)))))) "function-test")
110 |
111 |
112 | (check-ast?
113 | (app (id-ref '+)
114 | (list (number 5) (number 6))) "app test")
115 |
116 |
117 | (check-ast?
118 | (assume (list (make-bind 'x (number 5))
119 | (make-bind 'y (number 6)))
120 | (app (id-ref '+)
121 | (list (id-ref 'x) (id-ref 'y)))) "assume-test")
122 |
123 |
124 |
125 | ;;; A feasible concrete syntax for recursive:
126 | ;;; (recursive ([even? (n) (if (0? n) #t (odd? (- n 1)))]
127 | ;;; [odd? (n) (if (0? n) #f (even? (- n 1)))])
128 | ;;; (even? 5))
129 |
130 | (check-ast?
131 | (assume-rec
132 | (list
133 | (make-bind 'even?
134 | (make-function '(n)
135 | (ifte (app (id-ref '0?) (list (id-ref 'n)))
136 | (boolean #t)
137 | (app (id-ref 'odd?)
138 | (list (app (id-ref '-) (list (id-ref 'n) (number 1))))))))
139 |
140 | (make-bind 'odd?
141 | (make-function '(n)
142 | (ifte (app (id-ref '0?) (list (id-ref 'n)))
143 | (boolean #f)
144 | (app (id-ref 'even?)
145 | (list (app (id-ref '-) (list (id-ref 'n) (number 1)))))))))
146 | (app (id-ref 'even?) (list (number 3))))
147 | "recursive-ast test")
148 |
149 |
150 | (check-ast?
151 | (assume (list (make-bind 'x (number 5)))
152 | (seq (list (set 'x (number 3))
153 | (id-ref 'x)))))
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/code/store-list.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 | ;;; ==============================
3 | ;;; List implementation of Stores
4 | ;;; ==============================
5 |
6 | ;;; A store is implemented as a list.
7 |
8 | (require racket/match)
9 |
10 | (provide
11 | store?
12 | ref?
13 | new-store
14 | new-ref
15 | new-refs
16 | deref
17 | setref
18 | setrefs
19 | )
20 |
21 | ;;; nat? : any/c -> boolean?
22 | (define nat?
23 | (lambda (n)
24 | (and (integer? n)
25 | (>= n 0))))
26 |
27 | (define ref? nat?)
28 |
29 | (define storable-value? any/c)
30 |
31 |
32 | ;;; store? : any/c -> boolean?
33 | (define store? list?)
34 |
35 |
36 | ;;; new-store : () -> store?
37 | (define new-store
38 | (lambda()
39 | '()))
40 |
41 |
42 | ;;; store-length : store? -> nat?
43 | (define store-length
44 | (lambda(s)
45 | (length s)))
46 |
47 | ;;; returns a new store with a new reference containing val
48 | ;;; new-ref: [store? storable-value?] -> [store? ref?]
49 | (define new-ref
50 | (lambda (s v)
51 | (list (cons v s) (length s))))
52 |
53 |
54 |
55 | ;;; returns a new store with new references containing vals
56 | ;;; new-refs :
57 | ;;; [store? (listof storable?)] -> [store? (listof ref?)]
58 | (define new-refs
59 | (lambda (s vals)
60 | (letrec
61 | ([loop
62 | (lambda(s vals ls)
63 | (cond
64 | [(null? vals) (values s ls)]
65 | [else (let ([result1 (new-ref s (first vals))])
66 | (loop (first result1) (rest vals) (append ls (rest result1))))]))])
67 |
68 | (loop s vals '()))))
69 |
70 |
71 |
72 | ;;; deref: [store? ref?] -> storable-value?
73 | ;;; deref: "throws address out of bounds" error
74 | (define deref
75 | (lambda (s r)
76 | (let ([pos (- (sub1 (length s)) r)])
77 | (if (>= pos 0)
78 | (list-ref s pos)
79 | (error 'deref "throws address out of bounds")))))
80 |
81 |
82 | ;;; setref: [store? ref? storable-value?] -> store?
83 | ;;; setref: "throws address out of bounds" error if
84 | ;;; reference out of s's bounds.
85 | (define setref
86 | (lambda (s r v)
87 | (if (>= (length s) r)
88 | (replace s (- (length s) (add1 r)) v)
89 | ;(if (eq? (sub1 (length s)) r)
90 | ;(cons v (rest s))
91 | ;(cons (first s) (setref (rest s) r v)))
92 | (error 'setref "throws address out of bounds"))))
93 |
94 |
95 | ;;; setrefs: [store? (listof ref?) (listof storable-value?)] -> store?
96 | ;;; setrefs: "throws address out of bounds" error if
97 | ;;; rs are out of the store s's bounds.
98 | (define setrefs
99 | (lambda (s rs vs)
100 | (if (eq? (length rs) 0)
101 | s
102 | (setrefs (setref s (first rs) (first vs)) (rest rs) (rest vs)))))
103 |
104 |
105 |
106 |
107 | ;;; replace
108 | ;;; -------
109 | ;;; construct a list like ls except that ls contains v at
110 | ;;; index i
111 |
112 | ;;; replace : ([ls : (listof any/c)]
113 | ;;; [i : (
115 | ;;; (listof any/c)
116 |
117 | (define replace
118 | (lambda (ls i v)
119 | (if (eq? i 0)
120 | (cons v (rest ls))
121 | (cons (first ls) (replace (rest ls) (sub1 i) v)))))
122 |
123 |
124 | ;;; unit Testing
125 | ;;; ============
126 |
127 | ;;; Racket's unit testing framework
128 | (require rackunit)
129 |
130 | ;;; implementation tests
131 | ;;; --------------------
132 |
133 | (define-simple-check (check-store? thing)
134 | (store? thing))
135 |
136 | (check-store? (new-store))
137 |
138 | (check-equal? (store-length (new-store)) 0 "test:store-length-empty-store")
139 | (check-equal? (new-ref (new-store) 'a) '((a) 0) "test:new-ref-empty-store")
140 | (check-equal? (first (new-ref (new-store) 'a)) '(a) "test:new-ref^1")
141 | (check-equal? (first (new-ref (first (new-ref (new-store) 'a)) 'b)) '(b a) "test:new-ref^2")
142 | (check-equal? (first (new-ref (first (new-ref (first (new-ref (new-store) 'a)) 'b)) 'c))
143 | '(c b a) "test:new-ref^3")
144 |
145 | (check-equal?
146 | (match-let ([(list s r) (new-ref (new-store) 4)])
147 | (new-ref s 8))
148 | '((8 4) 1))
149 |
150 | (check-equal?
151 | (match-let ([(list s r1) (new-ref (new-store) 4)])
152 | (match-let ([(list s r2) (new-ref s 8)])
153 | (setref s r1 7)))
154 | '(8 7))
155 |
156 |
157 | (check-equal?
158 | (match-let ([(list s r1) (new-ref (new-store) 4)])
159 | (match-let ([(list s r2) (new-ref s 8)])
160 | (setref s r2 15)))
161 | '(15 4))
162 |
163 | (check-equal?
164 | (match-let ([(list s r1) (new-ref (new-store) 4)])
165 | (match-let ([(list s r2) (new-ref s 8)])
166 | (setref s r2 (+ (deref s r1) (deref s r2)))))
167 | '(12 4))
168 |
169 |
170 | ;;; API tests
171 | ;;; ---------
172 | (define s0 (new-store))
173 | (define ans (new-ref s0 'a))
174 | (define s1 (match-let ([(list s _) ans]) s))
175 | (define r1 (match-let ([(list _ r) ans]) r))
176 |
177 | (check-equal? r1 0)
178 | (check-equal? (deref s1 0) 'a)
179 | (check-exn exn? (lambda ()
180 | (deref s1 1)))
181 |
182 | (define s2 (setref s1 0 'b))
183 | (check-equal? (deref s2 0) 'b)
184 | (check-exn exn? (lambda () (setref s2 3 'c)))
185 |
186 |
187 | (check-equal?
188 | (match-let ([(list s r) (new-ref (new-store) 4)])
189 | (let ([s (setref s r 7)])
190 | (deref s r)))
191 | 7)
192 |
193 |
194 | (check-equal?
195 | (match-let ([(list s r) (new-ref (new-store) 4)])
196 | (match-let ([(list s r) (new-ref s 8)])
197 | (deref s 0)))
198 | 4)
199 |
200 | (check-equal?
201 | (match-let ([(list s r) (new-ref (new-store) 4)])
202 | (match-let ([(list s r) (new-ref s 8)])
203 | (deref s r)))
204 | 8)
205 |
206 |
207 |
208 |
209 |
210 |
211 |
--------------------------------------------------------------------------------
/code/eval-ast.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 | ;;; =============================================================
4 | ;;; Evaluator for the STORE-PASSING/IMPLICIT-ALLOCATION language
5 | ;;; =============================================================
6 |
7 | (provide
8 | eval-ast)
9 | (require "ast.rkt")
10 | (require "store-list.rkt")
11 | (require "env.rkt")
12 | (require "init-store-env.rkt")
13 | (require "semantic-domains.rkt")
14 | (require eopl/eopl)
15 |
16 |
17 | ;;; answer? = store? expressible-value?
18 |
19 | ;;; eval-ast : [ast? env? store?]-> answer?
20 | ;;; eval-ast : throws error
21 |
22 |
23 | (define eval-ast
24 | (lambda (a env store)
25 | (cases ast a
26 | [number (datum) (values store datum)]
27 | [boolean (datum) (values store datum)]
28 | [id-ref (id) (values store (deref store (lookup-env env id)))]
29 | [ifte (test then else)
30 | (let-values ([(new-store b) (eval-ast test env store)])
31 | (if (boolean? b)
32 | (eval-ast (if b then else) env new-store)
33 | (error 'eval-asts "wrong answer")
34 | ))]
35 | [function (formals body)
36 | (values store (closure formals body env))]
37 | [app (rator rand)
38 | (let*-values ([(new-store1 p) (eval-ast rator env store)]
39 | [(new-store2 args) (eval-asts rand env new-store1)])
40 | (apply-proc p args new-store2 env))]
41 | [assume (binds body)
42 | (let*-values ([(ids) (map bind-id binds)]
43 | [(asts) (map bind-ast binds)]
44 | [(new-store1 vals) (eval-asts asts env store)])
45 | (let-values ([(new-store2 reference) (new-refs new-store1 vals)])
46 | (eval-ast body (extended-env ids reference env) new-store2)))]
47 |
48 | [assume-rec (binds body)
49 | (let* ([ids (map bind-id binds)]
50 | [asts (map bind-ast binds)]
51 | [vals (map (lambda(x)
52 | (cases ast x
53 | [function (formals body)
54 | (rec-closure formals body)]
55 | [else (error 'parse "uninitialized variable ~a" x)]
56 | )
57 | ) asts)])
58 | (let*-values ([(p q) (new-refs store vals)])
59 | (let ([new-env (extended-env ids q env)])
60 | (eval-ast body new-env p)
61 | ))
62 | )]
63 |
64 | [set (lhs rhs)
65 | (let-values ([(new-store1 res) (eval-ast rhs env store)])
66 | (if (symbol? lhs) (values (setref new-store1 (lookup-env env lhs) res) res)
67 | (error 'eval-ast "wrong input")))]
68 | [seq (stmts)
69 | (let-values ([(new-store res) (eval-asts stmts env store)])
70 | (values new-store (last res)))]
71 | [else (error 'eval-ast "wrong input")]
72 | )))
73 |
74 |
75 |
76 |
77 | ;;; eval-asts : [(listof ast?) env? store?] -> store? (listof expressible-value?)
78 |
79 | (define eval-asts
80 | (lambda (asts env store)
81 | (letrec
82 | ([loop (lambda (asts env store val)
83 | (if (eq? (length asts) 0)
84 | (values store val)
85 | (let-values ([ (new-store result) (eval-ast (first asts) env store)])
86 | (loop (rest asts) env new-store (append val (list result) )))))])
87 | (loop asts env store '())
88 | )))
89 |
90 | ;(let-values ([(new-store res) (eval-ast (first asts) env store)])
91 | ; (if (> (length (rest asts)) 0)
92 | ; (let-values ([(rest-store rest-res) (eval-asts (rest asts) env new-store)])
93 | ; (values rest-store (append (list first) rest-res)))
94 | ; (values new-store (list res))))))
95 |
96 |
97 |
98 |
99 | ;;; apply-proc :
100 | ;;; [proc? (list-of expressible-value?) store?]
101 | ;;; -> answer?
102 |
103 | (define apply-proc
104 | (lambda (p args store env)
105 | (cases proc p
106 | [prim-proc (prim sig)
107 | (values store (apply-prim-proc prim sig args))]
108 |
109 | [closure (formals body env)
110 | (apply-closure formals body env args store)]
111 | [rec-closure(formals body)
112 | (apply-closure formals body env args store)]
113 | )))
114 |
115 |
116 |
117 | ;;; apply-prim-proc :
118 | ;;; [procedure? (listof procedure?)
119 | ;;; (listof expressible-value?)] -> expressible-value?
120 | ;;;
121 | ;;; apply-prim-proc : throws error when number or type of
122 | ;;; args do not match the signature of prim-proc
123 |
124 | (define apply-prim-proc
125 | (lambda (prim sig args)
126 | (cond
127 | [(and (= (- (length sig) 1) (length args))
128 | (andmap match-arg-type (rest sig) args))
129 | (apply prim args)
130 | ]
131 | [else (error 'apply-prim-proc "unable to handle some cases")]
132 | )))
133 |
134 | ;;; match-arg-type : [procedure? any/c] -> boolean?
135 | (define match-arg-type
136 | (lambda (arg-type val)
137 | (arg-type val)))
138 |
139 |
140 | ;;; apply-closure : [closure? (listof expressible-value?)]
141 | ;;; -> answer?
142 |
143 | (define apply-closure
144 | (lambda (formals body env args store)
145 | (let-values ([(new-store references)(new-refs store args)])
146 | (eval-ast body (extended-env formals references env) new-store))))
147 |
148 | ; ( let ([new-env (extended-env formal args env)])
149 | ; (eval-ast body new-env new-store))))
150 |
151 |
152 |
153 |
154 | ;;; Unit testing
155 | ;;; ============
156 |
157 | (require rackunit)
158 |
159 | (define-simple-check
160 | (check-eval-ast? ast env store expected label)
161 | (let-values ([(store val) (eval-ast ast env store)])
162 | (check-equal? val expected label)))
163 |
164 |
165 | (define s1-e1
166 | (make-init-store-env '(x y z) '(1 2 3)))
167 |
168 | (define s1 (first s1-e1))
169 | (define e1 (second s1-e1))
170 |
171 | (check-eval-ast? (number 5) e1 s1 5 "eval-ast: n5 test")
172 | (check-eval-ast? (boolean #t) e1 s1 #t "eval-ast: bt test")
173 | (check-eval-ast? (id-ref 'x) e1 s1 1 "eval-ast: id1 test")
174 | (check-eval-ast? (id-ref 'y) e1 s1 2 "eval-ast: y test")
175 |
176 |
177 | (check-eval-ast?
178 | (assume (list (make-bind 'x (number 4)))
179 | (id-ref 'x))
180 | e1
181 | s1
182 | 4
183 | "eval-ast: new-ref1")
184 |
185 |
186 | (check-eval-ast?
187 | (assume (list (make-bind 'x (number 4)))
188 | (assume (list (make-bind 'y (id-ref 'x)))
189 | (id-ref 'y)))
190 | e1
191 | s1
192 | 4
193 | "eval-ast: new-ref2")
194 |
195 | (check-eval-ast?
196 | (assume (list (make-bind 'x (number 4)))
197 | (assume (list (make-bind 'ignore (set 'x (number 7))))
198 | (id-ref 'x)))
199 | e1
200 | s1
201 | 7
202 | "eval-ast: new-ref3")
203 |
204 |
205 | (check-eval-ast?
206 | (assume (list (make-bind 'x (number 4)))
207 | (seq
208 | (list
209 | (set 'x (number 7))
210 | (id-ref 'x))))
211 | e1
212 | s1
213 | 7
214 | "eval-ast: new-ref3")
215 |
216 | ;; trying to set a non-reference
217 |
218 | (check-exn exn?
219 | (lambda ()
220 | (eval-ast
221 | (assume (list (make-bind 'x (number 4)))
222 | (set (number 7) (boolean #f)))
223 | e1
224 | s1)
225 | "eval-ast: error-set"))
226 |
227 |
228 |
229 | (check-exn exn?
230 | (lambda ()
231 | (eval-ast
232 | (assume-rec (list (make-bind 'x) (id-ref 'x))
233 | (id-ref 'x))
234 | e1
235 | s1
236 | "eval-ast: uninitialized")))
237 |
238 |
239 |
--------------------------------------------------------------------------------