Homework 10
Extending Huey, A Language for RGB Values

Due: Thursday, April 25, at 11:59 PM

Introduction

This assignment extends Huey, our little RGB color language, and the interpreter and other tools that process programs written in the language. The new version of the language supports local variables.

Before going any farther, read the updated Huey language specification. It defines the language, in particular the extensions, and talks about some of the Racket you can use to implement your homework.

Code and Files

For this assignment, you will extend the Huey interpreter to handle local variables, including the syntax procedures that define the new expressions, the pre-processor, and the evaluator. You will organize your code in the same way as you did for Homework 9.

Here are a few changes specific to this assignment:

We will extend the Huey language and intepreter again on the next homework assignment. Please comment your source code so that you and I can easily find the pieces relevant to this assignment.

A Data Abstraction for Environments

In order to support local variables, our interpreter needs a way to map names onto values. To provide this behavior, we need an abstract data type called an environment. The environment ADT is an example of a finite function.

This data type consists of four operations:

The var-exists? function is an addition to the interface of finite functions we studied in class. It enables us to determine whether an environment contains a particular variable, without ever having to look up a non-existent variable and cause an error.

Problems

  1. Implement the environment ADT as a finite function using association lists.
    An association list is a list of name/value pairs, such as:
    ((foo . 2) (bar . 5) (baz . 15))
    
    For example:
    > (make-bindings)
    ()
    > (bind 'foo 2 (make-bindings))
    ((foo . 2))
    > (bind 'bar 5 (bind 'foo 2 (make-bindings)))
    ((bar . 5) (foo . 2))
    > (define env (bind 'bar 5 (bind 'foo 2 (make-bindings))))
    > (look-up 'foo env)
    2
    > (var-exists? 'bif env)
    #f
    > (look-up 'bif env)
    environment: undefined variable -- baz
    
    You may write your own recursive code to implement the look-up function, or you may use the Racket's primitive assoc function.

  2. Define the syntax procedures for variable references and color/in expressions.
    For each of the new expression types, define a type predicate, a constructor, and the corresponding access procedures.

    Be sure to extend the general type predicate huey-exp? (or whatever you named it) to recognize the new types of expression, too.

  3. Extend (preprocess sugared-exp) to handle variable references and color/in expressions.
    Both of the new types of expression are core features of Huey, so preprocess needs only to de-sugar the sub-expressions of a variable declaration: the body and the variable's value.

    For example:
    > (preprocess 'white)
    'white
    
    > (preprocess '(color purple = ((rgb 255 0 0) mix (rgb 0 0 255)) in
                      (darker purple)))
    '(color purple = (((rgb 255 0 0) * 0.5) + ((rgb 0 0 255) * 0.5)) in
        (purple * 0.5))
    
    > (preprocess '(color purple = ((rgb 255 0 0) mix (rgb 0 0 255)) in
                      (color reverse-purple = (invert purple) in
                        (darker reverse-purple))))
    '(color purple = (((rgb 255 0 0) * 0.5) + ((rgb 0 0 255) * 0.5)) in
        (color reverse-purple = (invert purple) in
          (reverse-purple * 0.5)))
    

  4. Extend (eval-exp exp) to handle variable references and color/in expressions.
    eval-exp returns the value of exp, which now may be or contain the new kinds of expression, as specified by the language's semantics.

    What Racket will display as a result of eval-exp depends on how you represent RGB values internally. If you use a representation like the rgb expressions in the language, for example, it might display values such as these:
    > (eval-exp 'white)
    '(rgb 255 255 255)
    
    > (eval-exp '(color red = (rgb 255 0 0) in
                    (darker red)))
    '(rgb 127 0 0)
    
    > (eval-exp '(color red = (rgb 255 0 0) in
                    (color pink = (white mix red) in
                      (darker pink))))
    '(rgb 127 63 63)
    
    > (eval-exp 'gray)
    eval-exp: undefined variable -- gray
    
    eval-exp must now maintain its own environment and look up the value of a variable references in the environment. Have eval-exp do the following:
    • create an initial environment in which to evaluate its argument. This environment should contain the primitive values of Huey.
    • pass the initial environment, along with the pre-processed version of its argument, to the helper function that actually evaluates an expression in a given environment.
    A color/in expression creates a new variable, which must be added to the environment before its body is evaluated. The helper will pass the extended environment on its recursive call.

  5. Define a function (run-huey) that opens a REPL for your Huey interpreter.
    Have the eval step in your REPL call your eval-exp function. Feel free to use the ideas from the reading on imperative programming, but customize the REPL so that it is unmistakably yours!

    The print step in your REPL should display a color in the following form:
    R: ___  G: ___ B: ___
    
    Extra credit points will be awarded if the the red, green, and blue components are displayed in the corresponding color!

    The read step in your REPL should validate the input before calling the evaluator. If the user enters an illegal expression, that is, anything that is not a legal Huey program, the REPL should not cause an error. Instead, have it write an error message to the screen and let the user enter another expression.

Deliverables

By the due time and date, use the course submission system to submit the following files electronically:

Be sure that your submission follows the submission requirements. As always, use the specified names for your files. This enables the autograder to find and run your code.