|
| 1 | +#lang racket |
| 2 | +(provide (all-defined-out)) |
| 3 | + |
| 4 | +;; type Prog = [FunDef] Expr |
| 5 | + |
| 6 | +;; type FunDef = Variable [Variable] Expr |
| 7 | + |
| 8 | +;; type Expr = |
| 9 | +;; | Integer |
| 10 | +;; | Boolean |
| 11 | +;; | Character |
| 12 | +;; | Variable |
| 13 | +;; | Prim1 Expr |
| 14 | +;; | Prim2 Expr Expr |
| 15 | +;; | Lam Name [Variable] Expr <--- New for Loot |
| 16 | +;; | App Expr [Expr] <--- Changed for Loot |
| 17 | +;; | If Expr Expr Expr |
| 18 | +;; | Let (Binding list) Expr |
| 19 | +;; | LetRec (Binding list) Expr <--- New for Loot (See the lecture notes!) |
| 20 | +;; | Nil |
| 21 | + |
| 22 | +;; Note: Fun and Call, from Knock, are gone! |
| 23 | +;; They have been made redundant by the combination |
| 24 | +;; of Lam (which is new) and App (which has been modified) |
| 25 | + |
| 26 | +;; type Prim1 = 'add1 | 'sub1 | 'zero? | box | unbox | car | cdr |
| 27 | +;; type Prim2 = '+ | '- | cons |
| 28 | + |
| 29 | +;; type Binding = Variable Expr |
| 30 | + |
| 31 | +;; type Variable = Symbol (except 'add1 'sub1 'if, etc.) |
| 32 | + |
| 33 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 34 | +;;;;;; The represenation of top-level programs |
| 35 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 36 | + |
| 37 | +(struct prog (ds e) #:transparent) |
| 38 | + |
| 39 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 40 | +;;;;;; The represenation of a function definition |
| 41 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 42 | + |
| 43 | +;; A FunDef has a symbol for the function's name, |
| 44 | +;; a list of symbols representing the names of the function's |
| 45 | +;; arguments, and one expression that forms the body of the function. |
| 46 | +(struct fundef (name args body) #:transparent) |
| 47 | + |
| 48 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 49 | +;;;;;; The Expr data structure |
| 50 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 51 | + |
| 52 | +;; An Expr can be viewed as having 'kinds' of nodes. |
| 53 | +;; |
| 54 | +;; * The nodes that represnt an expression themselves |
| 55 | +;; |
| 56 | +;; * The nodes that are part of an expression, but no an expression themselves |
| 57 | + |
| 58 | +;; The below are the former: |
| 59 | + |
| 60 | +(struct int-e (i) #:transparent) |
| 61 | +(struct bool-e (b) #:transparent) |
| 62 | +(struct char-e (c) #:transparent) |
| 63 | +(struct var-e (v) #:transparent) |
| 64 | +(struct prim-e (p es) #:transparent) |
| 65 | +(struct lam-e (vs es) #:transparent) |
| 66 | +(struct lam-t (n vs es) #:transparent) |
| 67 | +(struct app-e (f es) #:transparent) |
| 68 | +(struct ccall-e (f es) #:transparent) ; <- new for Shakedown |
| 69 | +(struct if-e (e t f) #:transparent) |
| 70 | +(struct let-e (bs b) #:transparent) |
| 71 | +(struct letr-e (bs b) #:transparent) |
| 72 | +(struct nil-e () #:transparent) |
| 73 | + |
| 74 | +;; The next is the latter: |
| 75 | + |
| 76 | +;; A binding holds a symbol representing the bound variable and |
| 77 | +;; Expr that represents the value that will be bound to that variable |
| 78 | +(struct binding (v e) #:transparent) |
| 79 | + |
| 80 | + |
| 81 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 82 | +;;;;;; AST nodes for closures (used for pedagogical purposes) |
| 83 | +;;;;;; (see interp-defun.rkt) |
| 84 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 85 | + |
| 86 | +(struct closure (fs e env) #:transparent) |
| 87 | +(struct rec-closure (lam fenv) #:transparent) |
| 88 | + |
| 89 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 90 | +;;;;;; AST utility functions (predicates) |
| 91 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 92 | + |
| 93 | +(define unops '(add1 sub1 zero? box unbox empty? car cdr)) |
| 94 | +(define biops '(+ - cons)) |
| 95 | + |
| 96 | +;; Any -> Boolean |
| 97 | +(define (prim? x) |
| 98 | + (and (symbol? x) |
| 99 | + (memq x (append unops biops)))) |
| 100 | + |
| 101 | +;; Any -> Boolean |
| 102 | +(define (biop? x) |
| 103 | + (and (symbol? x) |
| 104 | + (memq x biops))) |
| 105 | + |
| 106 | +;; Any -> Boolean |
| 107 | +(define (unop? x) |
| 108 | + (and (symbol? x) |
| 109 | + (memq x unops))) |
| 110 | + |
| 111 | +(define (value? v) |
| 112 | + (or (int-e? v) |
| 113 | + (bool-e? v))) |
| 114 | + |
| 115 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 116 | +;;;;;; AST utility functions (getters) |
| 117 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 118 | + |
| 119 | +;; It will sometimes be useful to get the list of all the variables that are |
| 120 | +;; introduced by a `let` |
| 121 | +;; [Binding] -> [Symbol] |
| 122 | +(define (get-vars bs) |
| 123 | + (match bs |
| 124 | + ['() '()] |
| 125 | + [(cons (binding v _) bs) (cons v (get-vars bs))])) |
| 126 | + |
| 127 | +;; Get all of the _definitions_ from a list of bindings |
| 128 | +;; [Binding] -> [Expr] |
| 129 | +(define (get-defs bs) |
| 130 | + (match bs |
| 131 | + ['() '()] |
| 132 | + [(cons (binding _ def) bs) (cons def (get-defs bs))])) |
| 133 | + |
| 134 | + |
| 135 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 136 | +;;;;;; AST utility functions (maps) |
| 137 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 138 | + |
| 139 | +(define (bindings-map-def f bs) |
| 140 | + (match bs |
| 141 | + ['() '()] |
| 142 | + [(cons (binding n def) bs) |
| 143 | + (cons (binding n (f def)) (bindings-map-def f bs))])) |
| 144 | + |
| 145 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 146 | +;;;;;; AST utility functions (printers) |
| 147 | +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 148 | + |
| 149 | +;; We have switched to using `#:transparent` above, so this should only be |
| 150 | +;; necessary if you're desperate when debugging :'( |
| 151 | + |
| 152 | +;; Given a Program, construct an sexpr that has the same shape |
| 153 | +(define (prog-debug p) |
| 154 | + (match p |
| 155 | + [(prog ds e) `(prog ,(map fundef-debug ds) ,(ast-debug e))])) |
| 156 | + |
| 157 | +;; Given a FunDef, construct an sexpr that has the same shape |
| 158 | +(define (fundef-debug def) |
| 159 | + (match def |
| 160 | + [(fundef name args body) `(fundef ,name ,args ,(ast-debug body))])) |
| 161 | + |
| 162 | +;; Given an AST, construct an sexpr that has the same shape |
| 163 | +(define (ast-debug a) |
| 164 | + (match a |
| 165 | + [(int-e i) `(int-e ,i)] |
| 166 | + [(bool-e b) `(bool-e ,b)] |
| 167 | + [(char-e c) `(char-e ,c)] |
| 168 | + [(var-e v) `(var-e ,v)] |
| 169 | + [(nil-e) ''()] |
| 170 | + [(prim-e p es) `(prim-e ,p ,@(map ast-debug es))] |
| 171 | + [(lam-t n vs e)`(lam-t ,n ,vs ,(ast-debug e))] |
| 172 | + [(lam-e vs e) `(lam-e ,vs ,(ast-debug e))] |
| 173 | + [(app-e f es) `(app-e ,(ast-debug f) ,@(map ast-debug es))] |
| 174 | + [(if-e e t f) `(if-e ,(ast-debug e) |
| 175 | + ,(ast-debug t) |
| 176 | + ,(ast-debug f))] |
| 177 | + [(let-e bs b) `(let-e ,(binding-debug bs) ,(ast-debug b))] |
| 178 | + [(letr-e bs b) `(letr-e ,(binding-debug bs) ,(ast-debug b))])) |
| 179 | + |
| 180 | +(define (binding-debug bnds) |
| 181 | + (match bnds |
| 182 | + ['() '()] |
| 183 | + [(cons (binding v e) bnds) `((,v ,(ast-debug e)) ,@(binding-debug bnds))])) |
0 commit comments