On this page:
From Con+   and Dupe+   to Fraud+
From Binary to Variadic Addition
Generalizing Let
Back-Referencing Let
Testing
Submitting
7.9

Assignment 4: Let there be (Many) Variables

Due: Tuesday, March 23rd at 11:59PM EST

The goal of this assignment is to extend a compiler with binding forms.

Assignment repository:

You are given a repository with a starter compiler similar to the Fraud language we studied in class. You are tasked with:

From Con+ and Dupe+ to Fraud+

Implement the abs, unary - and not operations and the cond form from Assignment 3.

Unlike Assignment 3, the AST struct definitions and parsing code are provided. Study the relevant parts in ast.rkt and parse.rkt, understand what is different (if anything) from your own implementation and implement the relevant functionality in interp.rkt, interp-prim.rkt, and compile.rkt. You can start from your previous code, but you will need to update it to work for the structures provided. What’s essentially left for you to do is to make sure to correctly signal an error ('err) when these constructs are applied to the wrong type of argument.

While you’re at it, implement the predicates integer? and boolean? for checking the type of an argument, modeled by char? which was covered in the lectures.

In case it’s helpful, the formal semantics of cond are defined as:

image

image

image

The following files have already been updated for you:
  • ast.rkt

  • parse.rkt

You will need to modify:
  • compile.rkt

  • interp.rkt

  • interp-prim.rkt

  • types.rkt

to correctly implement these features.

You do not necessarily need to change all of these files depending on your design choices, but you shouldn’t alter any other files for Gradescope to work. If you feel that modifying a different file leads to a more natural/intuitive design - reach out! We’ll be happy to see a different approach and possibly extend our infrastructure to handle that.

From Binary to Variadic Addition

In Fraud, we implemented a binary operation for addition. However, Racket supports an arbitrary number of arguments for +. Your job is to extend the parser, interpreter, and compiler to behave similarly.

The following file have already been updated for you:

You will need to modify
  • compile.rkt

  • parse.rkt

  • interp.rkt

  • interp-prim.rkt

to correctly implement these features.

Generalizing Let

The Fraud language has a let form that binds a single variable in the scope of some expression. This is a restriction of the more general form of let that binds any number of expressions. So for example,

(let ((x 1) (y 2) (z 3))
  e)

simultaneously binds x, y, and z in the scope of e.

The syntax of a let expression allows any number of binders to occur, so (let () e) is valid syntax and is equivalent to e.

The binding of each variable is only in scope in the body, not in the right-hand-sides of any of the let.

For example,

(let ((x 1) (y x)) 0)

is a syntax error because the occurrence of x is not bound.

To capture that behavior, you need to implement:

Back-Referencing Let

Similar to let there is also let* that also binds any number of expressions. The difference is that previous bindings are available to subsequent bindings. For example,

(let* ((x 1) (y 2) (z (add1 y)))
  e)

binds x to 1, y to 2, and z to 3 in the scope of e.

The syntax of a let* expression allows any number of binders to occur, so (let* () e) is valid syntax and is equivalent to e.

Unlike let,

(let* ((x 1) (y x)) 0)

is not a syntax error and should not produce an IllFormedError.

Update the parser, interpreter, and compiler to implement this different form of let-binding.

Testing

You can test your code in several ways:

Note that only a small number of tests are given to you, so you should write additional test cases.

We provide a random-exprs.rkt module which provides exprs, a list of 500 randomly-generated closed expressions. You can use them freely to test various properties of your interpreter or compiler.

Submitting

You should submit on Gradescope. You should submit a zip file that has exactly the same structure that the stub contains. We will only use the parse.rkt, compile.rkt, interp.rkt, types.rkt and interp-prim.rkt files for grading, so make sure all your work is contained there! Note the lack of ast.rkt - part of assignment 3 was learning to design your own structures, part of assignment 4 is learning to work within the constraints of an existing design!