Desugaring

Introduction

The goal of this first assignment is to properly set up your development environment and to familiarize yourself with the L3 language and its compiler. Although this assignment is not graded, you should take it seriously as it guides you through the L3 code base and gives you the information you need to work efficiently on the project.

Initial setup

To work on the project, you first need to install sbt, the Scala build tool that we will use. Depending on how you choose to install sbt, you might have to install Java beforehand, in which case we recommend installing version 21 from the Adoptium web site.

Notice that if you are working on Windows, we strongly recommend that you install the Windows Subsystem for Linux (WSL), as all the instructions for this course assume that you are working in such a Unix-like environment, and we cannot provide support for anything else.

Skeleton

The skeleton for this first assignment is available as a Zip archive that you should download and open. This will create a directory called l3-warmup containing everything.

Desugaring implementation

The first task of this assignment consists in completing the desugaring process in the L3 compiler.

For that, navigate to the compiler subdirectory of your freshly created project and launch sbt in interactive mode. This can be done by entering the following commands in your shell:

$ cd l3-warmup/compiler
$ sbt

Sbt is the standard tool to compile, test and run Scala projects. You can compile the L3 compiler using the compile command in the sbt shell:

sbt:l3c> compile

Notice that this is an sbt command, not a shell command! This is why the prompt is not $ anymore, but sbt:l3c>, sbt’s default prompt (l3c is the name of the project, and stands for L3 compiler).

The first time you compile the project, a lot of project-specific dependencies will be downloaded, so be patient! Once compilation succeeds, you can finally run the L3 compiler using sbt’s run command, to which you should give the path to the input file. For now, you will try to compile a very simple “hello, world!” L3 program found in ../examples/hello.l3, by entering the following command:

sbt:l3c> run ../examples/hello.l3

You will notice that the compiler fails with a “not implemented” exception. Your next task is to add the missing pieces to the syntactic sugar translation.

For that, navigate to the bottom of file src/l3/L3Parser.scala. You will notice that some methods are implemented in terms of a method called ???, which throws a runtime exception. Implement those methods according to the rewrite rules given in this week’s lecture.

While implementing these methods, you will often have to transform sequences of trees of type Seq[Tree] or similar. The foldRight and reduceRight methods are very useful for that, but if you prefer to do pattern matching, remember that the syntax is as follows:

trees match {
  case Seq(head, tail @ _*) => // … non-empty Seq
  case Seq() =>                // … empty Seq
}

After implementing only the sBegin and sFun methods in src/l3/L3Parser.scala, you should already be able to run the hello.l3 example. Now implement all the other desugaring methods.

As you are developing the desugaring, it would be good to test your implementation. We provide you with a few tests that you can run using sbt’s test command:

sbt:l3c> test

Notice that the test called int-print will fail even if your implementation of desugaring is correct. To make it pass, you will have to implement the int-print function of the standard library, which is your next task.

Library implementation

Once you are done with the desugaring, run the example program called printint.l3 and enter a number when asked to. Notice that this example needs functions from the L3 standard library, and therefore the name of its module file, lib.l3m, has to be given to the compiler too, as follows:

sbt:l3c> run ../library/lib.l3m ../examples/printint.l3

Alternatively, you can just pass the module file of the above program, which is completely equivalent to the above, but shorter:

sbt:l3c> run ../examples/printint.l3m

As you can see, the program cannot print the number you have entered. This is because the implementation for the L3 library function int-print is missing, and your next goal is to write it.

For that, open the file library/integers.l3 and look for the int-print function. Complete its definition so that it can properly print the integer it gets as argument, in base 10. Be sure to correctly handle negative numbers too!

We suggest that you implement int-print in terms of two other library functions, both of which are defined in library/characters.l3:

  • char-print, which prints a single character, and
  • int->char-digit, which returns the character corresponding to the digit given as argument, an integer between 0 and 9.

References

More information about Scala can be obtained here:

Coursera course
This is a course about functional programming in Scala given by Martin Odersky, the creator of Scala. You can access the course material and exercises by signing up for the course.
Scala API
The API for the Scala standard library.