Skip to content

Commit 55043f7

Browse files
authored
Merge pull request #21 from dvanhorn/next
Next
2 parents a5187de + decee0f commit 55043f7

6 files changed

Lines changed: 124 additions & 38 deletions

File tree

www/notes/extort.scrbl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121

2222
@title[#:tag "Extort"]{Extort: when errors exist}
2323

24+
@emph{The greatest mistake is to imagine that we never err.}
25+
26+
@table-of-contents[]
27+
28+
@section{Errors}
29+
2430
We have added multiple, disjoint types, but mostly swept issues of
2531
errors under the rug by considering type mismatches as meaningless.
2632
Now let's redesign the semantics to specify the error behavior of such
@@ -119,7 +125,7 @@ The statement of correctness stays the same, but now observe that
119125
there is no way to crash the interpreter with any @tt{Expr} value.
120126

121127

122-
@section{An Example of Extort compilation}
128+
@section{A Compiler for Extort}
123129

124130
Suppose we want to compile @racket[(add1 #f)], what needs to happen?
125131
Just as in the interpreter, we need to check the integerness of the

www/notes/fraud.scrbl

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020

2121
@title[#:tag "Fraud"]{Fraud: local binding and variables}
2222

23+
@emph{To be is to be the value of a variable.}
24+
25+
@table-of-contents[]
26+
27+
@section{Variables}
28+
2329
@;defmodule[(file "/Users/dvanhorn/git/cmsc430-www/www/notes/fraud/interp.rkt")]
2430
@;declare-exporting[(file "/Users/dvanhorn/git/cmsc430-www/www/notes/fraud/interp.rkt")]
2531
@;defidform/inline[interp]
@@ -373,22 +379,39 @@ address of a variable occurrence is count of variable names that occur
373379
before it in the list. When a variable is bound (via-@racket[let])
374380
the list grows:
375381

382+
@codeblock-include["fraud/translate.rkt"]
383+
384+
Notice that @racket[translate] is a kind of mini-compiler that
385+
compiles @tt{Expr}s to @tt{IExpr}s. It's only job is to eliminate
386+
variable names by replacing variable occurrences with their lexical
387+
addresses. It does a minor amount of syntax checking while it's at it
388+
by raising a (compile-time) error in the case of unbound variables.
389+
390+
The interpreter for @tt{IExpr}s will still have an environment data
391+
structure, however it will be simpler the association list we started
392+
with. The run-time environment will consist only of a list of values;
393+
the lexical address of (what used to be a) variable indicates the
394+
position in this list. When a value is bound by a @racket[let], the
395+
list grows:
396+
376397
@codeblock-include["fraud/interp-lexical.rkt"]
377398

399+
Try to convince yourself that the two version of @racket[interp]
400+
compute the same function.
378401

379402

380403
@section{An Example of Fraud compilation}
381404

382-
Suppose we want to compile @racket['(let ((x 7)) (add1 x))]. There
383-
are two new forms we need to compile: the @racket['(let ((x ...))
384-
...)] part and the @racket['x] part in the body.
405+
Suppose we want to compile @racket[(let ((x 7)) (add1 x))]. There
406+
are two new forms we need to compile: the @racket[(let ((x ...))
407+
...)] part and the @racket[x] part in the body.
385408

386-
We already know how to compile the @racket['(add1 ...)] part and the
409+
We already know how to compile the @racket[(add1 ...)] part and the
387410
@racket[7] part.
388411

389412
What needs to happen? Compiling the @racket[7] part will emit
390413
instructions that, when run, leave @racket[7] in the @racket['rax]
391-
register. Compiling the @racket['(add1 ...)] part relies on the
414+
register. Compiling the @racket[(add1 ...)] part relies on the
392415
result of evaluating it's subexpression to be in @racket['rax] when it
393416
increments it. So, compile the variable binding needs to stash the
394417
@racket[7] somewhere and compiling the variable occurrence needs to
@@ -401,16 +424,16 @@ a let, after the right-hand side has been run, the result should be
401424
pushed. When evaluating a variable occurrence, the bound value is on
402425
the stack. After exiting the let, the stack can be popped.
403426

404-
Suppose we want to compile @racket['(let ((x 7)) (let ((y 2)) (add1
427+
Suppose we want to compile @racket[(let ((x 7)) (let ((y 2)) (add1
405428
x)))]. Using the intuition developed so far, we should push 7, push
406429
8, and then run the body. But notice that the value of @racket['x] is
407-
no longer on the top of the stack; @racket['y] is. So to retrieve the
408-
value of @racket['x] we need jump past the @racket['y]. But
409-
calculating these offsets is pretty straightforward. In this example
410-
there is one binding between the binding of @racket['x] and this
411-
occurrence. Since we push every time we enter a let and pop every
412-
time we leave, the number of bindings between an occurrence and its
413-
binder is exactly the offset from the top of the stack we need use.
430+
no longer on the top of the stack; @racket[y] is. So to retrieve the
431+
value of @racket[x] we need jump past the @racket[y]. But calculating
432+
these offsets is pretty straightforward. In this example there is one
433+
binding between the binding of @racket[x] and this occurrence. Since
434+
we push every time we enter a let and pop every time we leave, the
435+
number of bindings between an occurrence and its binder is exactly the
436+
offset from the top of the stack we need use.
414437

415438
@filebox-include-fake[codeblock "fraud/asm/ast.rkt"]{
416439
#lang racket

www/notes/fraud/interp-lexical.rkt

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
11
#lang racket
22
(provide (all-defined-out))
3-
(require (only-in "interp.rkt" prim? value? interp-prim))
3+
(require (only-in "interp.rkt" prim? value? interp-prim)
4+
"translate.rkt")
45

5-
;; Expr -> IExpr
6-
(define (translate e)
7-
(translate-e e '()))
6+
;; type VEnv = (Listof Value)
87

9-
;; Expr LEnv -> IExpr
10-
(define (translate-e e r)
8+
;; Expr -> Answer
9+
(define (interp e)
10+
(interp-env (translate e) '()))
11+
12+
;; IExpr VEnv -> Answer
13+
(define (interp-env e r)
1114
(match e
1215
[(? value? v) v]
1316
[(list (? prim? p) e)
14-
(list p (translate-e e r))]
17+
(let ((a (interp-env e r)))
18+
(interp-prim p a))]
1519
[`(if ,e0 ,e1 ,e2)
16-
`(if ,(translate-e e0)
17-
,(translate-e e1)
18-
,(translate-e e2))]
19-
[(? symbol? x)
20-
(lexical-address x r)]
21-
[`(let ((,x ,e0)) ,e1)
22-
`(let ((_ ,(translate e0 r)))
23-
,(translate e1 (cons x r)))]))
24-
25-
;; Variable LEnv -> Natural
26-
(define (lexical-address x r)
27-
(match r
28-
['() (error "unbound variable")]
29-
[(cons y r)
30-
(match (symbol=? x y)
31-
[#t (length r)]
32-
[#f (lexical-address x r)])]))
20+
(match (interp-env e0 r)
21+
['err 'err]
22+
[v
23+
(if v
24+
(interp-env e1 r)
25+
(interp-env e2 r))])]
26+
[`(address ,i)
27+
(list-ref r i)]
28+
[`(let ((_ ,e0)) ,e1)
29+
(match (interp-env e0 r)
30+
['err 'err]
31+
[v
32+
(interp-env e1 (cons v r))])]))
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#lang racket
2+
(require rackunit)
3+
(require "../interp-lexical.rkt")
4+
(check-equal? (interp 5) 5)
5+
(check-equal? (interp '(let ((x 0)) x)) 0)
6+
(check-equal? (interp '(let ((x 0)) (let ((y 1)) x))) 0)
7+
(check-equal? (interp '(let ((x 0)) (let ((y 1)) y))) 1)
8+
(check-equal? (interp '(let ((x 0)) (let ((y x)) y))) 0)

www/notes/fraud/test/translate.rkt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#lang racket
2+
(require "../translate.rkt")
3+
(require rackunit)
4+
(check-equal? (translate '(let ((x 0)) x))
5+
'(let ((_ 0)) (address 0)))
6+
(check-equal? (translate '(let ((x 0)) (let ((y 1)) x)))
7+
'(let ((_ 0)) (let ((_ 1)) (address 1))))
8+
(check-equal? (translate '(let ((x 0)) (let ((y 1)) y)))
9+
'(let ((_ 0)) (let ((_ 1)) (address 0))))
10+
(check-equal? (translate '(let ((x 0))
11+
(let ((y x))
12+
y)))
13+
'(let ((_ 0))
14+
(let ((_ (address 0)))
15+
(address 0))))

www/notes/fraud/translate.rkt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#lang racket
2+
(provide (all-defined-out))
3+
(require (only-in "interp.rkt" prim? value? interp-prim))
4+
5+
;; type LEnv = (Listof Variable)
6+
7+
;; Expr -> IExpr
8+
(define (translate e)
9+
(translate-e e '()))
10+
11+
;; Expr LEnv -> IExpr
12+
(define (translate-e e r)
13+
(match e
14+
[(? value? v) v]
15+
[(list (? prim? p) e)
16+
(list p (translate-e e r))]
17+
[`(if ,e0 ,e1 ,e2)
18+
`(if ,(translate-e e0)
19+
,(translate-e e1)
20+
,(translate-e e2))]
21+
[(? symbol? x)
22+
`(address ,(lexical-address x r))]
23+
[`(let ((,x ,e0)) ,e1)
24+
`(let ((_ ,(translate-e e0 r)))
25+
,(translate-e e1 (cons x r)))]))
26+
27+
;; Variable LEnv -> Natural
28+
(define (lexical-address x r)
29+
(match r
30+
['() (error "unbound variable")]
31+
[(cons y r)
32+
(match (symbol=? x y)
33+
[#t 0]
34+
[#f (add1 (lexical-address x r))])]))

0 commit comments

Comments
 (0)