Skip to content

Commit d795e1f

Browse files
committed
Assignment 6.
1 parent c9f6253 commit d795e1f

2 files changed

Lines changed: 83 additions & 76 deletions

File tree

www/assignments.scrbl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
@include-section{assignments/3.scrbl}
99
@include-section{assignments/4.scrbl}
1010
@include-section{assignments/5.scrbl}
11-
@;include-section{assignments/6.scrbl}
11+
@include-section{assignments/6.scrbl}
1212
@;;include-section{assignments/7.scrbl}
1313

1414
@;{assignment 8: quote in general, and quasiquote}

www/assignments/6.scrbl

Lines changed: 82 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,94 @@
11
#lang scribble/manual
2-
@title[#:tag "Assignment 6" #:style 'unnumbered]{Assignment 6: Arities!}
2+
@title[#:tag "Assignment 6" #:style 'unnumbered]{Assignment 6: Syntax Checking}
33

44
@(require (for-label (except-in racket ...)))
5-
@(require redex/pict)
5+
@(require "../notes/ev.rkt"
6+
"../notes/utils.rkt")
67

7-
@(require "../notes/ev.rkt")
8+
@bold{Due: Tuesday, November 23nd, 11:59PM EDT}
89

9-
@bold{Due: Thursday, April 29th, 11:59PM EST}
10+
The goal of this assignment is to add syntax checking to our compiler.
1011

11-
@(define repo "https://github.com/cmsc430/assign06")
12+
You are given a repository with a starter compiler similar to the
13+
@seclink["Mountebank"]{Mountebank} language we studied in class. You
14+
are tasked with:
1215

13-
The goal of this assignment is (1) to implement arity checking in a
14-
language with functions, and (2) to implement the @racket[procedure-arity]
15-
operation for accessing the arity of a function.
16+
@itemlist[
1617

17-
Assignment repository:
18-
@centered{@link[repo repo]}
18+
@item{implementing compile-time syntax checking.}
19+
20+
]
21+
22+
@section[#:tag-prefix "a6-" #:style 'unnumbered #:tag "checking"]{Syntax Checking}
23+
24+
25+
Up until now, we've written our compiler assuming that programs are
26+
well-formed, but there has never been any code that actually checks
27+
this assumption. The assumptions go beyond the properties checked
28+
during parsing. For example, our parser will happily accept a program
29+
like @racket[(lambda (x x) x)], and the compiler will emit code for it
30+
even though this is not a well-formed program.
31+
32+
The idea of this assignment is to implement a function, defined in
33+
@tt{check-syntax.rkt}:
34+
35+
@#reader scribble/comment-reader
36+
(racketblock
37+
;; Prog -> Prog
38+
(define (check-syntax p) ...)
39+
)
40+
41+
If the program is well-formed, it should behave like the identity
42+
function, returning the same program it was given as input. On
43+
ill-formed programs, it should signal an error using @racket[error].
44+
45+
For the purposes of this assignment, the quality of the error messages
46+
doesn't matter, although in real programming language implementations,
47+
good error messages are crucial.
48+
49+
Here are the properties that should be checked of each program:
50+
51+
@itemlist[
52+
53+
@item{Every @racket[define]d function should have a distinct name.}
54+
55+
@item{Every function parameter should be distinct from the other
56+
parameters of that function.}
57+
58+
@item{Every function's name should be distinct from all of its
59+
parameters' names.}
60+
61+
@item{Every function name and variable should not clash with any of
62+
the keywords of our language, e.g. @racket[lambda], @racket[if], etc.
63+
(Note this is not a restriction Racket puts on programs; the following
64+
is a perfectly reasonable expression: @racket[(λ (λ) λ)], but we'll
65+
consider this a syntax error.)}
66+
67+
@item{Every pattern variable in a pattern should be distinct. (Racket
68+
also allows this, but it has a complicated run-time semantics which we
69+
don't implement so instead we just rule out these programs.)}
70+
71+
]
72+
73+
The starter code calls @racket[check-syntax] in both
74+
@tt{compile-file.rkt} and @tt{interp-file.rkt}. The definition of
75+
@racket[check-syntax] is stubbed out in @tt{check-syntax.rkt}.
76+
77+
There are a few tests included in @tt{test/check-syntax.rkt}. For
78+
this assignment, very few tests are included so you should write your
79+
own.
80+
81+
@section[#:tag-prefix "a6-" #:style 'unnumbered #:tag "update"]{Update a86}
82+
83+
There have been some changes to a86 that you'll need. You can update
84+
the @tt{langs} package with the following:
85+
86+
@verbatim|{raco pkg update langs}|
1987

20-
You are given a repository with a starter compiler similar to the
21-
@seclink["Loot"]{Loot} language we studied in class. The only change
22-
has been the addition of parsing code for the unary
23-
@racket[procedure-arity] primitive.
24-
25-
@section[#:tag-prefix "a6-" #:style 'unnumbered]{Arity-check yourself, before you wreck yourself}
26-
27-
When we started looking at functions and function applications, we
28-
wrote an interpreter that did arity checking, i.e. just before making
29-
a function call, it confirmed that the function definition had as many
30-
parameters as the call had arguments.
31-
32-
The compiler, however, does no such checking. This means that
33-
arguments will silently get dropped when too many are supplied and
34-
(much worse!) parameters will be bound to junk values when too few are
35-
supplied; the latter has the very unfortunate effect of possibly
36-
leaking local variable's values to expressions out of the scope of
37-
those variables. (This has important security ramifications.)
38-
39-
The challenge here is that the arity needs to be checked at run-time,
40-
since we have first class functions. But at run-time, we don't have
41-
access to the syntax of the function definition or the call. So in
42-
order to check the arity of a call, we must emit code to do the
43-
checking and to compute the relevant information for carrying out the
44-
check.
45-
46-
The main high-level idea is that: when compiling a function
47-
definition, the arity of the function is clear from the number of
48-
parameters of the definition; when compiling a call, the number of
49-
arguments is also obvious. Therefore, what's needed is a way for the
50-
the function and the call to communicate and check their corresponding
51-
arity information.
52-
53-
We recommend storing the arity of the function as an additional piece
54-
of information in the closure during its compilation. Then, during a
55-
call you can access that arity and check it before making the call.
56-
Bonus: it makes implementing @racket[procedure-arity] really
57-
straightforward: you just have to access that number.
58-
59-
Just like we've been saying all semester, there are multiple other
60-
ways of going about this, feel free to design and implement a solution
61-
that works correctly - and consider the trade-offs! For example,
62-
another approach would be to treat the arity of the function as if it
63-
were the first argument of the function. A function of @math{n}
64-
arguments would then be compiled as a function of @math{n+1}
65-
arguments. A call with @math{m} arguments would be compiled as a call
66-
with @math{m+1} arguments, where the value of the first argument is
67-
@math{m}. The emitted code for a function should then check that the
68-
value of the first argument is equal to @math{n} and signal an error
69-
when it is not. But how would you implement @racket[procedure-arity]
70-
in this case? (This is not a rhetorical question, if you have a
71-
realistic solution to this, send us an e-mail!)
72-
73-
Your job is to modify @racket[compile.rkt] and to implement this arity
74-
checking protocol and the @racket[procedure-arity] primitive. It might
75-
help to implement the primitive before compiling the calls themselves,
76-
to partially test your implementation. Unlike previous assignments,
77-
there are no explicitly marked TODOs (with the exception of
78-
@racket[procedure-arity]). You have to make sure you modify all places
79-
where closures are created/accessed to ensure that your changes work
80-
correctly!
81-
82-
As always, remember to test your code using both the testcases
83-
provided and by adding your own!
8488

8589
@section[#:tag-prefix "a6-" #:style 'unnumbered]{Submitting}
8690

87-
Submit just the @tt{compile.rkt} file on Gradescope.
91+
You should submit on Gradescope. You should submit a zip file that has
92+
exactly the same structure that the stub contains. We will only use
93+
the @tt{check-syntax.rkt} files for grading, so make sure all your
94+
work is contained there!

0 commit comments

Comments
 (0)