Lox Interpreter

Spring 2022 • CS 403

Language used: C#

Members

Name CWID Email Address Time Spent
Cara Cannarozzi 11970792 cacannarozzi@crimson.ua.edu 13 hours
Madeline Moore 11884126 mcmoore11@crimson.ua.edu 13 hours
Peter Zhang 11861641 pwzhang@crimson.ua.edu 10 hours

Implementation Task Distribution

Task Percentage of Task
Cara Cannarozzi Madeline Moore Peter Zhang
Research/Learning 33.33% 33.33% 33.33%
Design 33.33% 33.33% 33.33%
Implementation of Code 35.00% 35.00% 30.00%

Research/Learning

Since we already read most of the book, Crafting interpreters, together for project one, we were already familiar with the language. Throughout the development of our version of the Lox interpreter we heavily referenced the book. We chose to use the C# language to implement our version of Lox since it is similar to Java. Even though they are similar, there are still quite a few differences. We had to research C# in order to implement our version of Lox. Thankfully there are plenty of resources to help with this. We used Microsoft's C# documentation and also a table from Tangible Software Solutions that had common C# and Java equivalents. The documentation for C# can be found here and the table can be found here. After learning about C# we were ready to begin creating our interpreter.

Design

Although C# and Java were similar languages, there were still quite a few differences, and some of these caused us to have to make some selective design choices, such as:

  • Following Microsoft's C# naming convention with some of our own changes. such as using PascalCasing when naming a class or struct, beginning interface names with "I," using implicit typing for local variables when possible, capitalizing method names, and using try-catch for most exception handling.
  • Using a List in place of a Stack to implement scopes to resolve statements
  • Using a Dictionary in place of a HashMap
  • Using "readonly" for immutable variables in place of "final"
  • Using namespaces in place of packages
  • Using "foreach" loops
  • Using "var" for implicit typing rather than explicit when one can easily derive the type from RHS.

Implementation of Code

To implement this code, we met as a group many times until the project was complete. We used a pair programming approach by having one group member broadcast their screen onto a TV in a group study room in Gorgas. We implemented the interpreter in the same order that Crafting Interpreters implements jlox. This provided us with a recipe for the interpreter and a more detailed guide to the lox language. We used Rider as our IDE because it's more compatible with C#. Furthermore, we used Rider's debugger as our main tool to fix our project, since it provided a detailed stack trace that's capable of showing the value of every variable during every step of the project's execution. This was especially helpful when fixing our Environment class, since we could see the exact contents of an environment during any point of execution. Debugging dominated the total time spent working on this project. The bug we spent the longest time squashing was the evaluation of return statements. Our program would simply return a value when evaluating a return statement, instead of jumping forward to the original function call. To correct this, we used exceptions to throw the evaluated Return value and catch it in the LoxFunction class where the function is originally called.

Members

Name CWID Email Address Time Spent
Cara Cannarozzi 11970792 cacannarozzi@crimson.ua.edu 4 hours
Madeline Moore 11884126 mcmoore11@crimson.ua.edu 4 hours
Peter Zhang 11861641 pwzhang@crimson.ua.edu 8 hours

Testing Task Distribution

Task Percentage of Task
Cara Cannarozzi Madeline Moore Peter Zhang
Testing Script 5.00% 5.00% 90.00%
Test Cases 40.00% 40.00% 20.00%

Testing Script

We used a bash script to help automate our tests. The bash script is named "tester.sh" and it is located in the main directory. It is hardcoded to specifically work with our project directory. We got the JLox source code from the craftinginterpreters Github. The testing script ask to run either a specified single test case or all of the test cases. It will then compile our C# Lox Interpreter then compile the JLox Interpreter. Then the tester will then run the test case(s) on the JLox Interpreter and our own interpreter and compare the outputs. If the resulting outputs are the same then the test passes.

Below, to the right you can see the output of our tester when we ran it. To the left there is a list of our test cases. You can view each test case individually along with the output of our interpreter (the output is the same as the JLox Interpreter.

Requirements

This project has a few requirements. They are listed below.

  • Mono - For compiling the interpreter
    • You can get Mono from this here.
    • Another alternative is JetBrains Rider or Visual Studio.
  • Bash - For running the tester
    • Bash typically comes with Linux and MacOS. If you are Windows you can install Cygwin in order to run bash scripts. You can find the installation page here.
  • Dart - For running the tester
    • You can find instructions for installing dart here.
  • Java Development Kit (JDK) - For running the tester
    • You can find instructions for installing the JDK here.

Compiling the Interpreter

To compile the interpreter with Mono, type the following into the command line while in the main directory:

$ msbuild LoxInterpreter.csproj

To compile the interpreter with Rider or Visual Studio, open LoxInterpreter.csproj then you can click Build->Build Solution at the top of the IDE.

Interpreter Modes

The interpreter has two types of modes. It can either interpret Lox code from the command line (like a REPL) or from a lox file.

Interpreting code from the command line

To run the interpreter (reading from command line), type the following into the command line while in the main directory:

$ mono ./bin/Debug/LoxInterpreter.exe

To run the interpreter (reading from command line), using Rider, click Run at the top right of the IDE.

To run the interpreter (reading from command line), using Visual Studio, click Start at the top middle of the IDE.

Interpreting code from a file

To run the interpreter (reading a file), type the following into the command line while in the main directory:

$ mono ./bin/Debug/LoxInterpreter.exe LOXFILE.lox

Where LOXFILE.lox is the name of the file you want to read.

To run the interpreter (reading a file), using Rider, click the drop down to the left of Run button and click Edit Configuration, then put your Lox file in the program arguments and hit apply.

To run the interpreter (reading a file), using Visual Studio, click the drop down on the Start button and click LoxInterpreter Debug Properties, then put your Lox file in the Command line arguments and save the file.

Running the tester

The tester is a bash script that can be run from the command line. You can run the tester by typing the following into the command line while in the main directory:

$ bash tester.sh

Using the tester

Once you have ran the tester, it will prompt you for a test case to run. You can either type a specific test case number or type "ALL" to run all test cases. The tester will run run the case(s) and print if the interpreter passed or failed the test case(s).

Common Problems

These are some fixes for common problems.

  • If you are using a Windows machine, make sure the file line endings are LF and not CRLF. CRLF line endings will break the tester.