Skip to content

Commit 531a4fc

Browse files
authored
Fall 2025 (#208)
* Clean up zips target; add assignments to zips. * Link to source code for Hoax+ assignment. * Fix binding. * Download slides for webpage. * Put github token in env. * Add link to slides on web page. * Fix link binding. * Try add repository_dispatch. * Assignment 7.
1 parent 8f73e5f commit 531a4fc

File tree

2 files changed

+273
-5
lines changed

2 files changed

+273
-5
lines changed

.github/workflows/push.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
1+
name: Build and Deploy
12
on:
23
- push
3-
4-
name: Build and Deploy
4+
- repository_dispatch:
5+
types: [slides-updated]
56

67
jobs:
78
build:
89
runs-on: ubuntu-latest
910
env:
1011
GH_TOKEN: ${{ github.token }}
1112
steps:
13+
# Show payload only for repository_dispatch
14+
- name: Show dispatch payload
15+
if: ${{ github.event_name == 'repository_dispatch' }}
16+
run: |
17+
echo "Event type: ${{ github.event.action || 'N/A' }}"
18+
echo "Client payload (JSON):"
19+
echo '${{ toJson(github.event.client_payload) }}'
1220
- name: Set timezone
1321
uses: szenius/[email protected]
1422
with:

www/assignments/7.scrbl

Lines changed: 263 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,269 @@
11
#lang scribble/manual
2-
@(require "../defns.rkt")
3-
@title[#:tag "Assignment 7" #:style 'unnumbered]{Assignment 7: Binding sequentially, n-ary prmimitives}
2+
@(require "../defns.rkt"
3+
"../notes/ev.rkt")
4+
5+
@title[#:tag "Assignment 7" #:style 'unnumbered]{Assignment 7:
6+
Variable-arity and arity-overloaded functions}
47

58
@(require (for-label a86 (except-in racket ...)))
69

710
@bold{Due: @assign-deadline[7]}
811

9-
Details of this assignment will be released later in the semester.
12+
@(ev '(require iniquity-plus))
13+
14+
The goal of this assignment is to implement variable arity functions.
15+
16+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Overview}
17+
18+
For this assignment, you are given a @tt{iniquity-plus.zip} file on ELMS
19+
with a starter compiler similar to the @seclink["Iniquity"]{Iniquity}
20+
language we studied in class.
21+
22+
@section[#:tag-prefix "a7-" #:style 'unnumbered #:tag "rest"]{Rest
23+
arguments}
24+
25+
Many languages including JavaScript, C, C++, Java, Ruby, Go, PHP, and
26+
Racket provide facilities for defining functions that take a ``rest
27+
argument'' which allows the function to be called with more arguments
28+
than expected and these additional arguments will be bound to a single
29+
value that collects all of these arguments. In Iniquity, as in
30+
Racket, the obvious way of collecting these arguments into a single
31+
value is to use a list.
32+
33+
Here are some examples:
34+
35+
@itemlist[
36+
37+
@item{@racket[(define (f . xs) ...)]: this function takes @emph{any} number
38+
of arguments and binds @racket[xs] to a list containing all of them,}
39+
40+
@item{@racket[(define (f x . xs) ...)]: this function takes @emph{at
41+
least} one argument and binds @racket[x] to the first argument and
42+
@racket[xs] to a list containing the rest. It's an error to call this function
43+
with zero arguments.}
44+
45+
@item{@racket[(define (f x y z . xs) ...)]: this function takes
46+
@emph{at least} three arguments and binds @racket[x], @racket[y], and
47+
@racket[z] to the first three arguments and @racket[xs] to a list
48+
containing the rest. It's an error to call this function with 0, 1,
49+
or 2 arguments.}
50+
]
51+
52+
Here are some examples in Racket to get a sense of the behavior:
53+
54+
@ex[
55+
(define (f . xs) (list xs))
56+
(f)
57+
(f 1)
58+
(f 1 2)
59+
(f 1 2 3)
60+
(f 1 2 3 4)
61+
(define (f x . xs) (list x xs))
62+
(eval:error (f))
63+
(f 1)
64+
(f 1 2)
65+
(f 1 2 3)
66+
(f 1 2 3 4)
67+
(define (f x y z . xs) (list x y z xs))
68+
(eval:error (f))
69+
(eval:error (f 1))
70+
(eval:error (f 1 2))
71+
(f 1 2 3)
72+
(f 1 2 4)
73+
]
74+
75+
The code generated for a function call should not change: it should
76+
pass all of the arguments on the stack along with information about
77+
the number of arguments.
78+
79+
The compilation of function definitions that use a rest argument
80+
should generate code that checks that the given number of arguments is
81+
acceptable and should generate code to pop all ``extra'' arguments off
82+
the stack and construct a list which is then bound to the rest
83+
parameter.
84+
85+
It is worth remembering that arguments are pushed on the stack in such
86+
a way that the last argument is the element most recently pushed on
87+
the stack. This has the benefit of making it easy to pop off the
88+
extra arguments and to construct a list with the elements in the
89+
proper order.
90+
91+
HINT: the function definition knows the number of ``required''
92+
arguments, i.e. the minimum number of arguments the function can be
93+
called with---call this @math{m}---and the caller communicates how
94+
many actual arguments have been supplied---call this @math{n}. The
95+
compiler needs to generate a loop that pops @math{n-m} times,
96+
constructing a list with with popped elements, and then finally pushes
97+
this list in order to bind it to the rest parameter.
98+
99+
100+
@section[#:tag-prefix "a7-" #:style 'unnumbered #:tag "case-lambda"]{Arity dispatch}
101+
102+
Some languages such as Java, Haskell, and Racket make it possible to
103+
overload a single function name with multiple definitions where the
104+
dispatch between these different definitions is performed based on the
105+
number (or kind) of arguments given at a function call.
106+
107+
In Racket, this is accomplished with the @racket[case-lambda] form for
108+
constructing multiple-arity functions.
109+
110+
Here is an example:
111+
112+
@ex[
113+
(define f
114+
(case-lambda
115+
[(x) "got one!"]
116+
[(p q) "got two!"]))
117+
118+
(f #t)
119+
(f #t #f)
120+
(eval:error (f #t #f 0))
121+
]
122+
123+
This function can accept @emph{either} one or two arguments. If given
124+
one argument, it evaluates the right-hand-side of the first clause
125+
with @racket[x] bound to that argument. If given two arguments, it
126+
evaluates the right-hand-side of the second clause with @racket[p] and
127+
@racket[q] bound to the arguments. If given any other number of
128+
arguments, it signals an error.
129+
130+
A @racket[case-lambda] form can have any number of clauses (including
131+
zero!) and the first clause for which the number of arguments is
132+
acceptable is taken when the function is called.
133+
134+
Note that @racket[case-lambda] can be combined with rest arguments too.
135+
A clause that accepts any number of arguments is written by simply
136+
listing a parameter name (no parentheses). A clause that accepts some
137+
non-zero minimum number of parameters is written with a dotted
138+
parameter list.
139+
140+
For example:
141+
142+
@ex[
143+
(define f
144+
(case-lambda
145+
[(x y z . r) (length r)]
146+
[(x) "just one!"]))
147+
148+
(f 1 2 3 4 5 6)
149+
(f #t)
150+
(eval:error (f))
151+
(eval:error (f 1 2))]
152+
153+
This function takes three or more arguments @emph{or} one argument. Any
154+
other number of arguments (i.e. zero or two) results in an error.
155+
156+
@ex[
157+
(define f
158+
(case-lambda
159+
[(x y z) "three!"]
160+
[xs (length xs)]))
161+
162+
(f)
163+
(f 1 2)
164+
(f 1 2 3)
165+
(f 1 2 3 4 5 6)
166+
]
167+
168+
This function takes any number of arguments, but when given three, it
169+
produces @racket["three!"]; in all other cases it produces the number
170+
of arguments.
171+
172+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Representing the
173+
syntax of function definitions}
174+
175+
The @seclink["Iniquity"]{Iniquity} language has a single function
176+
definition form: @racket[(define (_f _x ...) _e)] which is represented
177+
with the following AST type:
178+
179+
@#reader scribble/comment-reader
180+
(racketblock
181+
;; type Defn = (Defn Id (Listof Id) Expr)
182+
(struct Defn (f xs e) #:prefab)
183+
)
184+
185+
Because there are three different forms of function definition in
186+
Iniquity+, we use the following AST representation:
187+
188+
@#reader scribble/comment-reader
189+
(racketblock
190+
;; type Defn = (Defn Id Fun)
191+
(struct Defn (f fun) #:prefab)
192+
193+
;; type Fun = (FunPlain [Listof Id] Expr)
194+
;; | (FunRest [Listof Id] Id Expr)
195+
;; | (FunCase [Listof FunCaseClause])
196+
;; type FunCaseClause = (FunPlain [Listof Id] Expr)
197+
;; | (FunRest [Listof Id] Id Expr)
198+
(struct FunPlain (xs e) #:prefab)
199+
(struct FunRest (xs x e) #:prefab)
200+
(struct FunCase (cs) #:prefab)
201+
)
202+
203+
What used to be represented as @racket[(Defn _f _xs _e)] is now
204+
represented as @racket[(Defn _f (FunPlain _xs _e))].
205+
206+
207+
The parser already works for these new forms of function definitions.
208+
Here are some examples of how function definitions are parsed, but you
209+
are encouraged to try out more to get a better sense:
210+
211+
@ex[
212+
(parse-define '(define (f x) x))
213+
(parse-define '(define (f . xs) xs))
214+
(parse-define '(define (f x y z . q) q))
215+
(parse-define
216+
'(define f
217+
(case-lambda
218+
[(x y) 2]
219+
[(z) 1]
220+
[(a b c . d) "3+"]
221+
[q "other"])))
222+
]
223+
224+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Starter code}
225+
226+
The compiler code given to you is just an implementation of Iniquity,
227+
but updated to parse the new forms of function definitions and
228+
re-organized slightly to match the new AST representation.
229+
230+
The interpreter code given to you works on the full Iniquity+
231+
language, so you do not need to update @racket[interp.rkt] and can use
232+
the interpreter to guide your implementation of the compiler.
233+
234+
@ex[
235+
(interp
236+
(parse '(define (f x) x)
237+
'(f 1)))
238+
(interp
239+
(parse '(define (f . x) x)
240+
'(f 1)))
241+
(interp
242+
(parse '(define (f . x) x)
243+
'(f)))
244+
(interp
245+
(parse '(define (f . x) x)
246+
'(f 1 2 3 4 5)))
247+
(interp
248+
(parse '(define f
249+
(case-lambda
250+
[(x y) 2]
251+
[(z) 1]
252+
[(a b c . d) "3+"]
253+
[q "other"]))
254+
'(cons (f 7)
255+
(cons (f 3 4)
256+
(cons (f)
257+
(cons (f 7 8 9 10 11)
258+
'()))))))
259+
]
260+
261+
262+
Thus, you should only need to modify @racket[compile.rkt].
263+
264+
A small number of test cases are given as usual.
265+
266+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Submitting}
267+
268+
To submit, use @tt{make} from within the @tt{iniquity-plus} directory
269+
to create a zip file containing your work and submit it to Gradescope.

0 commit comments

Comments
 (0)