Fun with ZODE5, CSC430, Spring 2024
1 Goal
2 Guidelines
2.1 Handling Errors
2.2 Progress Toward Goal comment
3 Mutation
4 New Library Functions
5 Be Creative
6 Command-line, anyone?
8.13

Fun with ZODE5, CSC430, Spring 2024🔗

1 Goal🔗

Add a few primitive functions to your language to allow you to write interactive programs.

The focus of this assignment is to be a bit more creative. Therefore, you are not required to have full test case coverage. Also, we would like you to submit a short program, written in ZODE5, that uses the new features.

2 Guidelines🔗

For this and all remaining assignments, every function you develop must come with the following things:

For this assignment, you must develop your solutions using the typed/racket language. If you haven’t seen them, you might be interested in these Hints on Using Typed Racket in CPE 430.

Your test cases must use the check-equal?, check-=, or check-exn forms.

Your solution should take the form of a single file.

Hand in your solution using the handin server. For help with the handin server, please see the course web page.

2.1 Handling Errors🔗

All of your error messages must contain the string "ZODE". Essentially, this allows my test cases to distinguish errors correctly signaled by your implementation from errors in your implementation. To be more specific: any error message that doesn’t contain the string "ZODE" will be considered to be an error in your implementation.

Additionally, your error messages should be actually helpful. Since you are the primary consumer of your own error messages, making these error messages good in the first place should reduce your overall development time. There are two parts to this: first, the error message should include text that actually indicates what the programmer did wrong. Second, include the text of the user’s program, so they (actually you) can figure out how to fix it. See lab 3 for an example of how to do this. (Apologies in advance if I renumber the labs and fail to update this paragraph....)

2.2 Progress Toward Goal comment🔗

Graders are happier when they know what to expect. Your final submission should start with a short one- or two-line comment indicating how far you got through the project. Ideally, this would just be: “Full project implemented.” But if you only implemented, say, squazz and blotz, and didn’t get to frob or dringo, please indicate this in the comment, so that we don’t spend all our time searching for bits that aren’t there.

3 Mutation🔗

There’s no need for mutation in any of the first five assignments in this class. Don’t mutate bindings, and don’t mutate structure fields. You don’t have to use hash tables at all, but if you do use hash tables use immutable hash tables only; no hash-set!.

4 New Library Functions🔗

Here are the new library functions you need to add to your language.

Note that as in the previous assignment, these are the "types" as they might appear in the ZODE5 manual; this does not say anything about how the language implementor (you) should represent them.

procedure

(println s)  boolean

  s : str
Print the string s to stdout, followed by a newline. This function does not guarantee any particular return value.

procedure

(read-num)  real

Print the prompt >, then read a line of numeric input from the terminal, return the number. Signal an error if the input is not a real number.

procedure

(read-str)  real

Print the prompt >, then read a line of input from the terminal, return the string (without the newline).

procedure

(seq a b ...)  any

  a : any
  b : any*
Evaluate a number of expressions, return the value of the last one. This will be needed in order to write programs such as

{seq
 {println "What is your favorite integer between 6 and 7?"}
 {locals : your-number = {read-num}
         : {println {++ "Interesting, you picked " your-number ". Bold choice!"}}}}

procedure

(++ a b ...)  string

  a : any
  b : any*
join together the arguments into a single string. Numbers should be coerced to strings, as shown in the previous example. You’re welcome to handle other kinds of values as well.

Note that the last two functions are of “variable arity”. That is, you can call them with a variable number of arguments. Accommodating this may require some adjustments to the design of your primitives.

You are welcome to use any racket primitives that are part of the default Racket environment in order to implement these functions. Some of the following may be useful to you:

printf displayln newline read-line string->number number->string real?

Here’s a short playthrough of a thrilling action-adventure game that I wrote in ZODE5 . I call it "Nightfall":

% racket ./oazo-cmdline.rkt ./oazo1.rkt

You are in the Space Shuttle. It is very cold.

You have 10 units of fuel left.

How many units of fuel do you burn?

> 8

You burned 8 units of fuel. You are slightly warmer.

You are in the Space Shuttle. It is very cold.

You have 2 units of fuel left.

How many units of fuel do you burn?

> 2

You burned 2 units of fuel. You are slightly warmer.

You are out of fuel. You have died.

Exciting, right?

Also, here’s an example of a ZODE5 program that shows how you might simulate lists (and recursion) in this language:

{locals
 : empty = 15
 : {locals
    : empty? = {lamb : x : {equal? x empty}}
    : cons = {lamb : f r :
                   {lamb : key :
                         {if : {equal? key 0}
                             : f
                             : r}}}
    : first = {lamb : pair :
                    {pair 0}}
    : rest = {lamb : pair :
                   {pair 1}}
    : {locals
       : sum-list = {lamb : l self :
                          {if : {empty? l}
                              : 0
                              : {+ {first l}
                                   {self {rest l} self}}}}
       : my-list = {cons 3 {cons 24 {cons 8 empty}}}
       : {println {++ "The sum of the list is " {sum-list my-list sum-list} "."}}}}}

5 Be Creative🔗

Using your new functions and some ideas from the previous section and of your own, we’d like you to write an original ZODE5 program of your own. What should it do? That’s up to you. However, it does not need to be long. Games are often good choices.

You should include your program as part of your submission. It should be at the end of the file, and it should take the form of quoted s-expression with the name ‘example-program‘.

For instance:

(define example-program
  '{seq {println "this program will be really nifty"}
        {println "after I write it"}})

You should also include the text that is generated in a sample run of the program, as a comment.

It may be that implementing your program requires additional ZODE5 primitive functions; for instance, an input program that accepts strings, or a substring function. You are welcome to add these to your ZODE5 language. These should not involve changing interp, just adding a function to the table of primitives.

6 Command-line, anyone?🔗

The following is optional. However, if you want to be able to run your programs at the command line, it’s not hard to do that.

Here’s one way. Add this to your implementation file:

(provide file-interp)
 
(define-type Simple-Sexp
  (U Symbol Number String (Listof Simple-Sexp)))
 
(define-predicate sexp? Simple-Sexp)
 
(define (file-interp [f : Path-String])
  (define v (file->value f))
  (cond [(sexp? v) (top-interp v)]
        [else (error 'file-interp "expected file to contain s-expression, got: ~e" v)]))

Then, add another file in the same directory containing this code:

#lang typed/racket
 
(require "impl.rkt")
 
(define dont-care
  (file-interp (vector-ref (current-command-line-arguments) 0)))

... where “impl.rkt” is the name of the file containing your ZODE5 implementation.

Now, you should be able to run this at the command-line, as for instance:

% racket ./zode-cmdline.rkt ./oazo2.rkt

The sum of the list is 35.

Again, this is entirely optional, you’ll only be handing in the main file.