Homework 11
Last updated: Sat, 26 Apr 2025 18:53:25 -0400
Out: Tue Apr 22 2025, 11am EST
Due: Tue Apr 29 2025, 11am EST
Overview
In this assignment, we will extend our "CS 450 Lang" programming language with more data types and primitive operations that are commonly found in other languages. Fortunately, using the The Design Recipe, this seemingly difficult task can be completed in a straightforward manner using the exact same methods we’ve been using all semester.
This hw will be graded accordingly:
correctness (autograder) (12 pts)
design recipe (21 pts)
testing (21 pts)
style (8 pts)
README (2 pt)
Setup
Create a new repository for this assignment by going to the CS450 Spring 2025 GitHub Organization and clicking "New".
Note: The CS450 Spring 2025 GitHub Organization must be the owner of the repository. Do not create the repository in your own account.
On the "Create a new repository" screen:
Name the repository hw<X>-<LASTNAME>-<FIRSTNAME> where <X> is the current homework number.
For example, I would name my hw11 repository hw11-Chang-Stephen.
Mark the repository as Private.
Check "Add a README file".
Select the Racket template for the .gitignore.
Choose whatever you wish for the license.
When done click "Create repository".
Tasks
Pre-programming Notes
- All code must be written following the The Design Recipe. (Just submitting code is not sufficient.) In additional to the required receipe steps, some language features may only be used in the certain scenarios, as called for by The Design Recipe.
For example, set! and other "imperative" features are not allowed ever.
Signatures should use define/contract and the predicates defined in the Data Design Recipe step.
For Examples and Tests, do not use check-expect from the Beginning Student Language (even though the textbook says to). Instead, use check-equal? or other testing forms from rackunit.
Examples for a function definition should be right after the define. But Tests should be put into the test-suite in tests.rkt. Try to think about corner cases and code coverage. Each function should have at minimum one Example, and "sufficient" Tests.
Tests should go in a tests.rkt file, as described in lecture, and the rest of the code should go in a file named hw11.rkt.
The submitted program must be only a series of defines (both constants and function definitions are allowed). It should not run any code (e.g., it should not start the big-bang loop automatically!). Not following this will result in GradeScope errors and/or timeouts.
You may look at lecture code to help you but DO NOT SUBMIT ANY OF THIS CODE (even if you change the variable names, etc). You won’t receive any credit. Instead, you should write code for this homework from scratch using The Design Recipe.
struct instances must be comparable with equal? and check-equal?, which means that they should be declared with the #:transparent keyword (including super structs).
Important: Each submission must be organized so that each function only processes one kind of data. Submissions consisting of only a few large, unreadable functions that try to do everything will not receive any credit.
Programming
In this assignment, you must use the following data definitions and functions.
Data Definitions
For each of these data definitions, you should complete them by writing the necessary predicates, constructors, etc. Items that differ from Homework 9 are in bold.
A Variable (Var) is a Symbol
An Environment (Env) is a List<(list Var Result)> (a list of 2-element lists) Represents the runtime environment for in-scope variables and the values they stand for. Entries closer to the head of the list shadow those further in the back.
- A Program is one of:
Atom
Variable
`(bind [,Var ,Program] ,Program)
(cons Program List<Program>)
Interpretation: represents the surface-level syntax of a new programming language (i.e., this is what programmers write). (But remember that these (nested lists of) symbols have no meaning until they are "run".) Pay particular attention to the last item, which subtly changes some valid/invalid programs from previous assignments. Thus parsing might need more than one "else" case to catch syntax errors. Hint: a bind cannot be the name of a function but all other symbols could be. - An Atom is one of:
Number
Bool!
Interp: represents basic data values in our language. - An Bool! is one of:
'TRUE!
'FALSE!
Interp: symbols that will stand for true/false boolean values in our language - An AST is one of:
(mk-num Number)
(mk-boo! Boolean)
(mk-var Symbol) (do not name your struct var because that is a Racket match pattern)
(mk-bind Symbol AST AST)
(mk-call AST List<AST>)
Interpretation: represents an abstract syntax tree data structure that is produced from parsing the surface program - A Result is one of:
(Racket) Number
(Racket) Boolean
(Racket) function
ErrorResult
Interpretation: possible results of running a program in our new language. - An ErrorResult is one of:
UNDEF-ERR
NOT-FN-ERR
Interpretation: possible "error" results of running a program in our new language. An "undefined" error should occur when trying to use an undefined variable. A "not fn" error should occur if attempting to call a non-function.Some subtleties:If one of these errors occurs in an inner expression, it should propagate to be the final result of the whole expression, but "deeper" errors should take precedence. For example, applying an undefined variable should produce UNDEF-ERR, not NOT-FN-ERR.
If more than one error occurs at the same "level", e.g., in arguments of a function call, the error result should be determined using a left-to-right precedence.
Functions (define and provide)
parse : takes a Program and produces an AST abstract syntax tree data value. When the input is not a valid Program, this function should call raise-syntax-error with an exn:fail:syntax:cs450 exception, which should be a substruct of exn:fail:syntax, and an appropriate error message. Be careful here because what is a valid/invalid Program has changed and requires more sophisticated parsing to determine.
exn:fail:syntax:cs450? : predicate evaluates to true if given a exn:fail:syntax:cs450 struct instance
AST? : predicate that evaluates to true for AST data definition values
run : takes an AST tree and "runs" it, to produce a Result "result".
As mentioned in lecture, this function should define an internal function that uses an Environment accumulator, so make sure to follow all steps of the Accumulator Design Recipe. The "intitial environment" should contain bindings for the + and \times symbols. As usual, the semantics of the language should follow JavaScript semantics. When in doubt, we will use the repljs.com evaluator as the official specification for the behavior of arithmetic on all kinds of values in our new programming language.
UNDEF-ERR? : predicate that evaluates to true when given an UNDEF-ERR result value
NOT-FN-ERR? : predicate that evaluates to true when given a NOT-FN-ERR result value
Before Submitting
Testing (and Autograders)
Before submitting, note:
Do not submit until all code has been thoroughly tested (by you), which means writing a "sufficient" number of Test cases.
A GradeScope "Autograder" may or may not be released before the due date but either way, an Autograder is not a software development/testing tool, so do not use it as one. Code must be tested independent of any Autograder and questions about Autograders will be ignored (e.g., posts asking "why is the Autograder giving an error?" are not allowed)
If you do submit before the deadline and get an Autograder error, this is bonus information that indicates the submitted code is not complete and/or not correct. But it’s up to you to figure out what "correct" means and how to fix to the program.
Of course, the course staff is here and eager to help, but cannot do so without context information. The best way to supply this information is to INCLUDE EXAMPLES WITH ALL QUESTIONS, along with what the "expected" result should be! The posted examples should be the minimal amount of code needed to communicate the problem. This will receive the clearest possible answer.
The Autograder test suite is subject to change. This means that the visible grade seen during submission is not the final grade.
Style
All code should follow proper Racket Style.
Also, the repository itself must follow proper style. Specifically, it must have appropriate commit messages. See How to Write a Git Commit Message if you are unsure how to write a commit message.
Files
A submission must have the following files in the repository root:
hw11.rkt: Contains the hw solution code.
All defines should use the name specified in the exercise (ask if you are unsure) and should be provided.
The easiest (but not always the most readable) way to ensure all necessary definitions are provided is to (initially) put as the second line in the file:
This automatically provides all definitions in the file (the first line should be #lang racket).
tests.rkt: This file should require hw11.rkt and define tests for it.
Specifically, it should define a rackunit test-suite named TESTS which contains "sufficient" rackunit Test cases (e.g., check-equal?, etc.) for each defined function.
README.md: Contains the required README information, including the GitHub repo url.
Submitting
When you are done, submit your work to Gradescope hw11. You must use the "GitHub" Submission Method and select your hw<X>-<LASTNAME>-<FIRSTNAME> repository.
Note that this is the only acceptable way to submit homework in this course. (Do not manually upload files and do not email files to the course staff. Homework submitted via any unapproved methods will not be graded.)