Project 5: Value Representation and Closure Conversion
Quick links
• Course Home
• Piazza
• Canvas
• Scala 3 Book
• X86 Cheat Sheet
Due: March 25, 2026 at 11:59pm
1 Introduction
Your task in this project is to implement the CPS value representation transformation, including closure conversion. First please download the skeleton code from Canvas. In the skeleton code, you will find a template for this compiler phase in class CPSValueRepresenter.scala. You can (and are encouraged to) use the helper methods in class CPSValueRepresenter, CPSTreeModule.Tree, and object BitTwiddling.
The value representation phase of the MiniScala compiler takes as input a CPS program where all values and primitives are "high-level", in that they have the semantics which the MiniScala language gives them. It produces a "low-level" version of that program as output, in which all values are either integers or pointers and primitives corresponding directly to instructions of a typical microprocessor.
This means that the primitive operations used in the CPSLow code (defined in CPSPrimitives) are only executing operations on integers (or pointers for block operations). All primitives are performing the operation that you could be expecting based on the name. The CPSByteWrite primitive returns the unit value. You can checkout the CPSLowInterpreter defined in CPSInterpreter.scala file and make sure you understand the CPSLow semantics.
In the lecture, we discussed a non-optimized version and an optimized version of closure conversion. Many functions in CPSValueRepresenter have an implicit argument worker (with the using keyword). This argument should not be useful in the non-optimized version, therefore you are free to pass the value Map.empty to call these functions while implementing the non-optimized version.
2 Grading
Please note that the the following aspects will be taken into consideration while grading:
Correctness of the implementation.
The time and memory efficiency of the implementation.
For instance, transforming a primitive operation x op y by naively decoding the arguments (x and y) and encoding the result back will get you fewer points if there exists a better translation that avoids, either completely or partially, some encodings/decodings. Note: To that end, make sure to use left shift (<<) and right shift (>>) operations to implement multiplication and division by 2 as described in the lectures.
For the closure conversion part, you can choose to implement either the "simple" or the optimized version (with worker and wrapper functions). Correctly implementing the simplified one will give you 90% of the grade for this assignment, whereas a correct implementation of the optimized transformation will give you 110% of the grade. An optimized version that works without supporting recursive/mutually recursive calls will give you 100% (you can still have function calls if they are not recursive). The extra 10% will be given if recursive and mutually recursive function calls can be handled properly.
However, note that by submitting an incorrect version of the optimized transformation you may lose a lot of points depending on the mistakes. Therefore, we recommend that you start by implementing the basic closure conversion procedure and, if you are successful and still have time, to extend it to the optimized procedure.
This assignment relies on the correct implementation of the previous one (MiniScalaToCPSTranslator). If you are confident that your implementation of MiniScalaToCPSTranslator is correct, feel free to use your implementation. You are also free to use the reference implementation that is part of the skeleton for Project 5.
3 Tips
Spend the time to understand the task that has to be accomplished. This means reading the material and the lectures carefully. A good idea to make sure you understand is to manually transform some piece of code. While doing that, write test cases! Two birds, one stone. Implement the actual value transformation function, keep the closure conversion for last. Test every cases! Of course the best way is to write at least one test case for it, but if you are not willing to write tests then verify that you can generate code that produces a correct result for simple programs.
The implementation can be very technical in some cases, so make sure that you are making good use of the helping function to avoid clustered code.
When creating fresh variable names, you can try to add some information that will help you to debug. For example, when creating a name for the worker of the function "test" you may prefer to use Symbol.fresh("test_worker") rather than generic name Symbol.fresh("w"). The skeleton code for the assignment is available here.
- Scala 3 permits a more concise way to use helper functions such as tempLetP, tempLetL, etc. Curly braces are optional: for example, tempLetP expects the last argument to be a function, so you can write
tempLetP(...): x => ... // note the indentationinstead of tempLetP(...){ x => ... }. See an example in the given case of LetP/MiniScalaIntAdd. Do not use sbt test every time you add a case to see if you pass more tests – many of the Blackbox tests will fail unless the closure conversion has been implemented.
4 Testing
From this assignment on, you will choose the shapes for the trees you generate. You should inspect them visually and decide whether or not they are correct and optimal. The given skeleton code does not have whitebox tests, but it still has an extensive blackbox test suite to ensure the correctness of the programs you generate.
Although we will not test tree shapes, we still encourage you to do so for every transformation rule you write. You have the necessary infrastructure in miniscala.test.CPSValueRepresentation_Whitebox, so it’s a matter of just writing the source code and the resulting tree. It is usually an effort that pays off.
You should write 10 tests otherwise points will be deducted.
5 Submission
You should turn in the proj5 directory. Please run an sbt clean before packaging and submitting.
To submit your project, create a ZIP file named proj5.zip of the proj5 directory and upload it to the corresponding assignment on Canvas.
Verify your submission by downloading the ZIP file you uploaded on Canvas and extracting its content. The uncompressed content should be the proj5 folder containing the code. Your submission ZIP file should have the exact same structure as the skeleton ZIP file.
Your submitted code must compile, i.e. running sbt compile gives no errors. If your code does not compile, your submission will not be graded and you will receive 0 points for the whole project.
Late Submission Policy: Projects are due at 11:59pm on the due date. Succeeding projects build upon previous ones and will reveal solutions of preceding projects, so late submissions will not be accepted. Submitted after the deadline will receive 0 points.