Skip to content

Commit 8cf803b

Browse files
committed
Revise notes for new exception behavior in interp.
1 parent ccc4f1f commit 8cf803b

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

www/notes/evildoer.scrbl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,7 @@ value:
700700
Using these pieces, we can write a function that matches the type signature
701701
of @racket[interp/io]:
702702

703-
@codeblock-include["evildoer/exec-io.rkt"]
703+
@codeblock-include["evildoer/exec.rkt"]
704704

705705
@ex[
706706
(exec/io (parse '(write-byte (read-byte))) "z")]

www/notes/extort.scrbl

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@
4040

4141
We have added multiple, disjoint types, but mostly swept issues of
4242
errors under the rug by considering type mismatches as meaningless.
43-
Now let's redesign the semantics to specify the error behavior of such
44-
programs.
43+
But undefined behavior, while convenient from the compiler writer's
44+
perspective, is the gateway to all kinds of bad outcomes for
45+
programmers. Let's redesign the semantics to specify the error
46+
behavior of such programs.
4547

4648

4749
We'll call it @bold{@this-lang}.
@@ -134,18 +136,32 @@ results that may be given by the interpretation function:
134136
Type mismatches can arise as the result of primitive operations being
135137
applied to arguments for which the primitive is undefined, so we
136138
revise @racket[interp-prim1] to check all necessary preconditions
137-
before carrying out an operation, and producing an error in case
138-
those conditions are not met:
139+
before carrying out an operation.
140+
141+
We will take advantage of Racket's exception system to @racket[raise]
142+
an error result whenever an error occurs. This is a nice way of
143+
shortcircuiting the remaining evaluation since as soon as we encounter
144+
an error, we know this is going to be the answer for the whole
145+
program.
139146

140147
@codeblock-include["extort/interp-prim.rkt"]
141148

142-
Within the interpreter, we update the type signature to reflect the
143-
fact that interpreting an expression produces an answer, no longer
144-
just an expression. We must also take care to observe that evaluating
145-
a subexpression may produce an error and as such it should prevent
146-
further evaluation. To do this, the interpreter is written to check
147-
for an error result of any subexpression it evaluates before
148-
proceeding to evaluate another subexpression:
149+
Notice that the signature for these functions indicate that you get a
150+
value, or they raise an exception. The functions for interpreting
151+
primitives check all of the necessary preconditions of a primitive
152+
before calling the corresponding Racket function. This ensures that
153+
the Racket functions are always @emph{safe}, they cannot raise an
154+
error. As a final catch-all case, we know that some precondition must
155+
not have held and we can raise the @racket['err] answer to indicate an
156+
error.
157+
158+
Within the interpreter, we restructure things so that there is now a
159+
top-level @racket[interp] function that installs an exception handler.
160+
Should interpreting the expression raise @racket['err], it handles
161+
this exception and returns the @racket['err] answer. The
162+
@racket[interp] function makes use of an auxilary function
163+
@racket[interp-e] that does the work of recursively interpreting the
164+
meaning of an expression:
149165

150166
@codeblock-include["extort/interp.rkt"]
151167

@@ -158,6 +174,16 @@ examples given earlier:
158174
(interp (parse '(if (zero? #f) 1 2)))
159175
]
160176

177+
Note that if you use the @racket[interp-e] function, expressions that
178+
cause errors will raise an exception:
179+
180+
@ex[
181+
(eval:error (interp-e (parse '(add1 #f))))
182+
(eval:error (interp-e (parse '(zero? #t))))
183+
(eval:error (interp-e (parse '(if (zero? #f) 1 2))))
184+
]
185+
186+
161187
This interpreter implicitly relies on the state of the input and
162188
output port, but we can define a pure interpreter like before,
163189
which we take as the specification of our language:
@@ -376,7 +402,6 @@ Linking in the run-time allows us to define the @racket[exec] and
376402
@racket[exec/io] functions:
377403

378404
@codeblock-include["extort/exec.rkt"]
379-
@codeblock-include["extort/exec-io.rkt"]
380405

381406
We can run examples:
382407

0 commit comments

Comments
 (0)