Closure Conversion
Introduction
For this third graded assignment, you have to complete the implementation of the values representation phase of the L3 compiler, by adding closure conversion.
Initial setup
To start working on the assignment, you should once again fetch the new code from our git repository, and then rebase your branch on ours. As a reminder, this can be done using the following two commands:
$ git fetch origin $ git rebase origin/master
Overview
After rebasing your branch on ours, you will have access to the following new code:
- in
CPSHoister.scala
you will find an empty definition of the hoisting phase, which you will have to complete, - in
L3Tester.scala
you will find a new definition ofbackEnd3
that includes the hoisting phase and uses the version of the CPS interpreter that assumes that closure conversion has been done.
To complete this assignment, you must first implement closure conversion by fixing the way function abstraction and application are handled in CPSValueRepresenter
. Once this is done, you have to write the hoisting phase that brings all the functions to the top level of the program. This is possible since after closure conversion they are all closed, i.e. they do not have free variables.
One operation you will have to perform during closure conversion is substitution of symbols, to replace the free variables of functions that you close by the fresh variables containing their value, extracted from the environment. To do this, you can use the functions available in package.scala
to create substitutions (represented as maps), and then write a helper function to apply such a substitution. That function is pretty straightforward to write, and could look as follows:
private def substitute(tree: L.Tree, s: Subst[Symbol]): L.Tree = { def substT(tree: L.Tree): L.Tree = tree match { case L.LetP(name, prim, args, body) => L.LetP(name, prim, args map substA, substT(body)) // ... other cases } def substC(cnt: L.Cnt): L.Cnt = ??? // code for continuation definitions def substF(fun: L.Fun): L.Fun = ??? // code for function definitions def substA(atom: L.Atom): L.Atom = ??? // code for atoms substT(tree) }
Testing and submission
You can test your phase as usual, using sbt's test
command.
To submit it, use sbt's packageSrc
command to create an archive containing the sources of your compiler. As a reminder, this archive is called l3c_2.13-2020-sources.jar
and is located in the target/scala-2.13
directory. Submit this archive to our submission server.
Grading
A total of 80 points are assigned to this project part, out of a total of 500 for the whole semester.
You can choose to implement either the "simple" version of closure conversion, or the optimized one. Notice however that only doing the former will cost you 10 points.
Be careful, though, as an incorrect implementation of the optimized version could give you less points than a correct implementation of the simple one. We therefore strongly recommend that you start by implementing the simple translation and, if it passes all tests and you still have time, work on the optimized one. And to be on the safe side, submit a version of your code as soon as the simple translation works.
Your submission will be graded based on:
- its correctness, i.e. whether it passes all the functional tests that were made available to you, and additional ones that we might have,
- the version of the closure conversion you implemented: as explained above, only implementing the simple one will cost you 10 points,
- its style, which will be worth 4 points for this assignment, so please pay attention to the feedback you received for the previous assignments.