|
1 | 1 | #lang scribble/manual |
2 | 2 | @(require "defns.rkt") |
| 3 | +@(require "notes/ev.rkt") |
| 4 | + |
3 | 5 | @title[#:style '(unnumbered)]{Project} |
4 | 6 |
|
| 7 | +The final assesment for this course consists of an individually |
| 8 | +completed project. |
| 9 | + |
| 10 | +Final deliverables are due by the end of the time schedule for the |
| 11 | +class's final exam as set by the registrar. |
| 12 | + |
| 13 | +Submissions should be made on Gradescope. |
| 14 | + |
| 15 | +There are several projects to choose from, described below. |
| 16 | + |
| 17 | +@section{Exceptions and Exception Handling} |
| 18 | + |
| 19 | +Exceptions and exception handling mechanisms are widely used in modern |
| 20 | +programming languages. Implement Racket's @racket[raise] and |
| 21 | +@racket[with-handlers] forms to add exception handling. |
| 22 | + |
| 23 | +You may choose to implement this feature for any language that is |
| 24 | +@seclink["Iniquity"]{Iniquity} or later for a maximum 95% of the |
| 25 | +possible points. For 100% you'll need to implement the feature for |
| 26 | +Perp and do the additional requirements below. |
| 27 | + |
| 28 | +@subsection{Requirements} |
| 29 | + |
| 30 | +Here are the key features that need to be added: |
| 31 | + |
| 32 | +@itemlist[ |
| 33 | + |
| 34 | +@item{@racket[(raise _e)] will evaluate @racket[_e] and then ``raise'' |
| 35 | +the value, side-stepping the usual flow of control and instead jump |
| 36 | +to the most recently installed exception handler.} |
| 37 | + |
| 38 | +@item{@racket[(with-handlers ([_p1 _f1] ...) _e)] will install a new |
| 39 | +exception handler during the evaluation of @racket[_e]. If |
| 40 | +@racket[_e] raises an exception that is not caught, the predicates |
| 41 | +should be applied to the raised value until finding the first |
| 42 | +@racket[_pi] that returns true, at which point the corresponding |
| 43 | +function @racket[_fi] is called with the raised value and the result |
| 44 | +of that application is the result of the entire @racket[with-handlers] |
| 45 | +expression. If @racket[_e] does not raise an error, its value is the |
| 46 | +value of the @racket[with-handler] expression.} |
| 47 | + |
| 48 | +] |
| 49 | + |
| 50 | +Here are some examples to help illustrate: |
| 51 | + |
| 52 | +@ex[ |
| 53 | + |
| 54 | +(with-handlers ([string? (λ (s) (cons "got" s))]) |
| 55 | + (raise "a string!")) |
| 56 | + |
| 57 | +(with-handlers ([string? (λ (s) (cons "got" s))] |
| 58 | + [number? (λ (n) (+ n n))]) |
| 59 | + (raise 10)) |
| 60 | + |
| 61 | +(with-handlers ([string? (λ (s) (cons "got" s))] |
| 62 | + [number? (λ (n) (+ n n))]) |
| 63 | + (+ (raise 10) 30)) |
| 64 | + |
| 65 | +(let ((f (λ (x) (raise 10)))) |
| 66 | + (with-handlers ([string? (λ (s) (cons "got" s))] |
| 67 | + [number? (λ (n) (+ n n))]) |
| 68 | + (+ (f 10) 30))) |
| 69 | + |
| 70 | +(with-handlers ([string? (λ (s) (cons "got" s))] |
| 71 | + [number? (λ (n) (+ n n))]) |
| 72 | + 'nothing-bad-happens) |
| 73 | + |
| 74 | +(with-handlers ([symbol? (λ (s) (cons 'reraised s))]) |
| 75 | + (with-handlers ([string? (λ (s) (cons "got" s))] |
| 76 | + [number? (λ (n) (+ n n))]) |
| 77 | + (raise 'not-handled-by-inner-handler))) |
| 78 | + |
| 79 | +] |
| 80 | + |
| 81 | +Notice that when a value is raised, the enclosing context is discard. |
| 82 | +In the third example, the surrounding @racket[(+ [] 30)] part is |
| 83 | +ignored and instead the raised value @racket[10] is given the |
| 84 | +exception handler predicates, selecting the appropriate handler. |
| 85 | + |
| 86 | +Thinking about the implementation, what this means is that a portion |
| 87 | +of the stack needs to be discarded, namely the area between the |
| 88 | +current top of the stack and the stack that was in place when the |
| 89 | +@racket[with-handlers] expression was evaluated. |
| 90 | + |
| 91 | +This suggestions that a @racket[with-handlers] expression should stash |
| 92 | +away the current value of @racket['rsp]. When a @racket[raise] |
| 93 | +happens, it grabs the stashed away value and installs it as the |
| 94 | +current value of @racket['rsp], effectively rolling back the stack to |
| 95 | +its state at the point the exception handler was installed. It should |
| 96 | +then jump to code that will carry out the applying of the predicates |
| 97 | +and right-hand-side functions. |
| 98 | + |
| 99 | +Since @racket[with-handler]s can be nested, you will need to maintain |
| 100 | +an arbitrarily large collection of exception handlers, each of which |
| 101 | +has a pointer into the stack and a label for the code to handle the |
| 102 | +exception. This collection should operate like a stack: each |
| 103 | +@racket[with-handlers] expression adds a new handler to the handler |
| 104 | +stack. If the body expression returns normally, the top-most handler |
| 105 | +should be removed. When a raise happens, the top-most handler is |
| 106 | +popped and used. |
| 107 | + |
| 108 | +@subsection{Additional requirements} |
| 109 | + |
| 110 | +To receive full credit, you will to add the above features to Perp and |
| 111 | +do the following. |
| 112 | + |
| 113 | +After you have a working implementation of @racket[raise] and |
| 114 | +@racket[with-handlers], add a structure definition to your standard |
| 115 | +library: @racket[(struct exn:fail (msg cm))]. Rework the compiler so |
| 116 | +that all run-time errors raise an instance of @racket[struct:fail]. |
| 117 | +This enables user-programs to handle run-time errors like this: |
| 118 | + |
| 119 | +@ex[ |
| 120 | + |
| 121 | +(with-handlers ([exn:fail? (λ (e) 'OK)]) |
| 122 | + (add1 #f)) |
| 123 | + |
| 124 | +] |
| 125 | + |
| 126 | +(The @racket[cm] field can be ignored; you can always populate it with |
| 127 | +@racket[#f] if you'd like. It's there just for consistency with |
| 128 | +Racket's @racket[exn:fail].) |
| 129 | + |
| 130 | + |
| 131 | + |
| 132 | + |
| 133 | + |
5 | 134 | There will be a final course project to be completed over the last |
6 | 135 | several weeks of the course. The project will involve extending the |
7 | 136 | design and implementation of the programming language and its compiler |
@@ -48,13 +177,13 @@ semester: |
48 | 177 |
|
49 | 178 | @item{Typing Loot. We have discussed typing for @tt{Hustle} and its |
50 | 179 | implications in the compiler (deleting a whole lot of assertions), as |
51 | | - well as typing for a simple lambda calculus. This project would aim |
| 180 | + well as typing for a simple λ calculus. This project would aim |
52 | 181 | to combine the two threads, implementing a type system on top of Loot. |
53 | 182 | There are interesting design decisions here, so feel free to reach out |
54 | 183 | to talk about them!} |
55 | 184 |
|
56 | 185 | @item{Loot Optimizations. Sky's the limit here. You can try |
57 | | - high-level optimizations (e.g. inlining, lambda lifting, dead-code |
| 186 | + high-level optimizations (e.g. inlining, λ lifting, dead-code |
58 | 187 | elimination, partial evaluation, etc.) or low-level ones (register |
59 | 188 | allocation, register-based calling conventions etc.). Optimizations |
60 | 189 | can be tricky to get right, so make sure you reuse all the unit |
|
0 commit comments