Skip to content
/ RnR Public

This project consists in developing a compiler able to process a subset of the Rust language. Its main role is to understand how a compiler works, as part of the LTU 'Compiler construction and formal languages' course. (This is a mirror of the gitlab version)

Notifications You must be signed in to change notification settings

ZynoXelek/RnR

Repository files navigation

RnR: Rust in Rust

This project aims to implement a compiler able to manage a subset of the Rust language, as part of the LTU Compiler construction and formal languages course.

The compiler is implemented in Rust, and supports the basics of the Rust language. It uses the Mips crate from the teacher for the backend code generation.

Table of content

Implemented Types

The implemented types are the following:

  • unit: the basic unit type -> ()
  • i32: basic integers -> 1, 2, -3
  • bool: booleans -> true, false
  • String: to be able to print things in the terminal -> "Hello World!"
  • Arrays: arrays can be defined using any of the existing types -> [1, -2, 3 * 4]

Implemented Operations

The implemented operations are the following:

  • Unary Operators
    • !: boolean negation -> !true
    • -: integer negation -> -5
  • Binary Operators
    • +, -, *, /: basic operations for integers only -> 3 * 4
    • &&, ||: basic operations for booleans only -> true || false
    • <, <=, >=, >: comparison operations for integers and Strings -> "abc" < "bac"
    • ==, !=: comparison operations for any type -> 3 * 4 == 13 - 1
    • [i]: get operation for arrays -> [1, 2, 3][1]

Examples of valid code

Here is an example of a small program that RnR can compile. You can find other in ./examples.

// An example program introducing a simple recursive factorial function

fn fact(n: i32) -> i32 {
    if n == 0 {
        1
    } else {
        n * fact(n - 1)
    }
}

fn main() {
    let n = 5;
    let a = fact(n);
    println!("{}! = {}", n, a);
}

How to use it

Information about the repository

The compiler can be used thanks to its CLI which uses the clap crate. It includes basic commands.

To be able to use them, you have two options once you have cloned this repository.

Building the release binary

You can build the binary from the cloned repository by calling the following command:

cargo build --release

Once it is done, the rnr executable will be located at ./target/release/rnr. You can then use it with the commands described below. For instance:

rnr -i <path_to_my_file> --type_check -ovcr

Not building the release binary

You can also directly use cargo to use RnR. To do so, you will have to call cargo run. However, to be able to add options as described below, you will have to use -- to tell the cargo run command that the following strings are not options, but should be passed to main.rs. If you don't, it will try to identify any option (-t for instance) as an option of the cargo run command. Here is an example:

cargo run -- -i <path_to_my_file> --type_check -ovcr

The first time you call it, it will build the whole project (not release version) and it will be quite long, but for future uses, it will be much quicker as it won't have to do it again.

Basic behavior

The default command is the following one:

rnr

This only parses the content of the main.rs file located in the current folder. It does not proceed any additional treatment.

Additional subcommands

Here are the possible subcommands you can add to apply other treatments.

Get help on commands

You can have additional information using the following subcommand:

-h
--help

Change the input file

You can change the input file from main.rs to any other file by adding this subcommand:

-i <relative_input_path>
--input <relative_input_path>

Dump the generated AST

You can dump the generated Abstract Syntax Tree from the parsed program in a file of your choice by adding the following subcommand:

-a <relative_output_path>
--ast <relative_output_path>

Note: If you use the optimizer option (-o/--optimize), the dumped AST will be the optimized AST extracted from your input program.

Process type checking

You can process type checking on the parsed result by adding the following subcommand:

-t
--type_check

This process will verify that your input program is formally correct.

Optimize the input program

You can process a program optimization on the parsed result by adding the following subcommand:

-o
--optimize

This process will try to eliminate any dead code from the input program. It requires that the type-check option is used.

Evaluate the parsed program using the RnR VM

You can process the evaluation of the parsed program using the RnR Virtual Machine by adding the following subcommand:

-v
--vm
--virtual_machine

This process requires that the type-check option is used. It also reveals array access errors by checking wether an index is within bonds or not. This is why this option is mandatory to generate the backend code, which does not implement these checks.

Generate the assembler code

You can generate the assembler code corresponding to the parsed program with the RnR backend by adding the following subcommand:

-c
--code_gen

This process requires that the evaluating option (-v) is used.

Dump the generated ASM

You can dump the generated ASM from the parsed program in a file of your choice by adding the following subcommand: (It requires that you have used the -c or --code_gen subcommand)

--asm <relative_output_path>

This process requires that the code generation option is used.

Run the generated ASM

You can run the generated ASM from the parsed program by adding the following subcommand: (It requires that you have used the -c or --code_gen subcommand)

-r
--run

This process requires that the code generation option is used.

Recommended commands

The most useful commands are therefore the two following ones:

  • Reading a custom file, type checking it, optimizing it, and running it through the virtual machine:
rnr -i <path_to_my_file> -tov
  • Reading a custom file, type checking it, optimizing it, generating the ASM code and running it:
rnr -i <path_to_my_file> -tovcr

Some additional remarks on the project

Parser

The RnR parser uses the syn crate. It implements a subset of it thanks to the generated TokenStream.

CLI

The Cli uses the clap crate to parse the input commands.

Backend

The backend is emulated in a virtual machine which copies a subset of the behavior of the MIPS 3k processor. This crate can be found here.

Note: The backend code does not support terminal printing. Therefore, println! calls can only be verified by evaluating the parsed AST in the RnR virtual machine (-v). However it can use any of the other defined types and operations.

Future implementations

RnR should still evolve in the future. There are several features from the original Rust language I would like to implement, such as:

  • References
  • New keywords (return, break, continue)
  • Custom structures
  • For loops and iterators

About

This project consists in developing a compiler able to process a subset of the Rust language. Its main role is to understand how a compiler works, as part of the LTU 'Compiler construction and formal languages' course. (This is a mirror of the gitlab version)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published