1414
1515@(define codeblock-include (make-codeblock-include #'h ))
1616
17+ @(ev '(require rackunit))
1718@(for-each (λ (f) (ev `(require (file ,(path->string (build-path notes "extort " f))))))
1819 '("interp.rkt " "compile.rkt " "asm/interp.rkt " "asm/printer.rkt " ))
1920
@@ -37,22 +38,6 @@ programs: values and errors. We will say that evaluation produces an
3738
3839@section{Meaning of Extort programs}
3940
40- The meaning of Extort programs...
41-
42- @itemlist[
43-
44- @item{... }
45-
46- ]
47-
48- Let's consider some examples:
49-
50- @itemlist[
51-
52- @item{... }
53-
54- ]
55-
5641Languages adopt several approaches to type mismatches:
5742
5843@itemlist[
@@ -68,7 +53,18 @@ We've previously seen the last approach. Now let's do what Racket
6853does and signal an error.
6954
7055
56+ The meaning of Extort programs that have type errors will now be
57+ defined as @racket['err ]:
58+
59+ @itemlist[
60+
61+ @item{@racket[(add1 #f )]: means @racket['err ].}
62+
63+ @item{@racket[(zero? #t )]: means @racket['err ].}
7164
65+ @item{@racket[(if (zero? #f ) 1 2 )]: means @racket['err ].}
66+
67+ ]
7268
7369@(define ((rewrite s) lws)
7470 (define lhs (list-ref lws 2 ))
@@ -99,40 +95,42 @@ And there are four rules for propagating errors from subexpressions:
9995
10096
10197
102- Now what does the semantics say about @racket[' (add1 #f )]? What about
103- @racket[' (if 7 #t -2 )]?
98+ Now what does the semantics say about @racket[(add1 #f )]? What about
99+ @racket[(if 7 #t -2 )]?
104100
105101
106- The interpreter ...
102+ The signature of the interpreter is extended to produce answers. Each
103+ use of a Racket primitive is guarded by checking the type of the
104+ arguments and an error is produced if the check fails. Errors are
105+ also propagated when a subexpression produces an error:
107106
108107@codeblock-include["extort/interp.rkt " ]
109108
110109We can confirm the interpreter computes the right result for the
111110examples given earlier:
112111
113112@ex[
114- '...
113+ (interp '(add1 #f ))
114+ (interp '(zero? #t ))
115+ (interp '(if (zero? #f ) 1 2 ))
115116]
116117
117- Correctness...
118-
119- @section{An Example of Extort compilation}
120-
121- Suppose we want to compile ...
118+ The statement of correctness stays the same, but now observe that
119+ there is no way to crash the interpreter with any @tt{Expr} value.
122120
123- What needs to happen? ...
124121
125- @;codeblock-include["extort/asm/ast.rkt"]
122+ @section{An Example of Extort compilation}
126123
127- We omit the printer code, which is mundane. See
128- @link["extort/asm/printer.rkt " ]{@tt{asm/printer.rkt}} for details.
124+ Suppose we want to compile @racket[(add1 #f )], what needs to happen?
125+ Just as in the interpreter, we need to check the integerness of the
126+ argument's value before doing the addition operation.
129127
130- We must extend the run-time system with a C function called @tt{error}
128+ We extend the run-time system with a C function called @tt{error}
131129that prints "err " and exits:
132130
133131@filebox-include[fancy-c "extort/main.c " ]
134132
135- Compiler...
133+ The compiler now emits code to check the type of arguments:
136134
137135@codeblock-include["extort/compile.rkt " ]
138136
@@ -156,4 +154,19 @@ Here are some examples running the compiler:
156154(asm-interp (compile '(if (zero? #t ) 1 2 )))
157155]
158156
157+ Since the interpreter and compiler have well defined specifications
158+ for what should happen when type errors occur, we can test in the
159+ usual way again:
160+
161+ @ex[
162+ (define (check-correctness e)
163+ (check-equal? (asm-interp (compile e))
164+ (interp e)
165+ e))
166+
167+ (check-correctness '(add1 7 ))
168+ (check-correctness '(add1 #f ))
169+ ]
170+
171+
159172
0 commit comments