Mini Rust Language Documentation

Mini-Rust is a subset of the popular programming language, Rust. It’s a compiler purely done in OCaml and that uses 86-64 Assembly to generate the source code. It supports functions, vectors, references(ownership), structures and more!


Table of Contents

Todo: TOC



1 - Output

Mini-Rust supports two functions for writting data to the user. The functions print! and println!. The print! function has one argument, a numeric or boolean value, and outputs it to the terminal, without the new line character. The println!function (print with new line) has one argument, a numeric or boolean value, and outputs it to the terminal with a new line character.

These output methods can be used with the i32 and boolean types.

print!(-4);

println!(true);



2 - Variables

The Mini Crust language supports integer variables of 32 bits, booleans, vectors, structures, and references.

The declaration of a immutable variables follows the syntax:

let «identifier» : «type» = «value»;

2.1 - Mutability

Mini crust language supports mutability. When a variable is marked as mutable its value can be changed afterwards. To declare a mutable variable we only need to use the keyword mut at the declaration act.

let mut x : i32 = -3;

x = 109;

An important note: The assignment is mandatory in the declaration of a variable in mini crust. In other words, the following program is illegal:

let x : i32;


Arithmetic Operations with Integers

As is normal in any language, we can perform numeric operations with integers.

The mini crust language supports a wide range of arithmetic operators, which are displayed in the following table.

Description Operator
Addition +
Subtraction -
Divisiton /
Module %
Multiplication *


3 - Comments

The Mini Crust language supports two types of comments, single line(// ...) and multi line(/* ... */) comments.
Comments are usefull because they are ignored by the compiler and give usefull information to the programmer.

Example:

// This is a single line comment

/* This
is
a
multiline
comment 
*/



5 - Boolean Expressions

The Mini Crust language supports boolean expressions and disposes a set of relational and logic operators.


5.1 - Relational Operators

Descrition Operator Usage
Equality == i32 == i32
Inequality != i32 != i32
Less than < i32 < i32
Less or equal <= i32 <= i32
Bigger than > i32 > i32
Bigger or equal >= i32 >= i32


5.2 - If Statement

The operators above can be used to build the conditions that would appear in the if statement, it’s important to remember that the else branch is completely optional. And that every used branch needs to have the same returning type.

if «condition»
{ 
    // Branch that will be executed
    // when the condition is true
}
else
{
    // Branch that will be executed
    // when condition is false
}

Example:

if 1 > 7
{
    printn(1);
}
else
{
    printn(2); // This will be executed 
}

5.3 - Else And Else If Statements

When we have a sequence of if statements in which only one of them will be executed, we can take advantage of the chain if - else if else. It is recommended to use a sequence of else if statements instead of isolated ifs statements, as it is more optimized and has a more pleasant appearance.

Structure:

let x : i32 = 3;

if x == 0
{
    println!(0);
}
else if x == 1
{
    println!(1);
}
else if x == 2
{
    println!(2);
}
else
{
    println!(3);
}

The reason for being more optimized:

If we rewrite the previous program in a sequence of if statements, the computer would be obliged to test all of the conditions even if we knew that only one would be true. With if - else if - else the computer only test the conditions until one evaluates to true.


5.4 - Logic Operators

If we want to build more complex conditions (where we test more than one condition), we can use the logical operators and, or and not.

The complete list of the logical operators can be seen in the table bellow:

Descrition Operator Usage
And && bool && bool
Or || bool || bool
Not ! ! bool

Example:

let mut y : i32 = 6;

if 1 > 7 && 2 == 3
{
    y = y + 1;
}


6 - While Loop

The Mini Crust language supports the while loop that can be used with the break and continue statements. These allow a richest control of the program flux..

The while loop is the most simple, and therefore the easiest to understand. Its purpose is to execute a set of statements while a certain condition is true. The implementation of the while loop in the mini crust language is as follows:

while «condition»
{
     // code
}

Exemple:

let mut i : i32= 0;

while i < 5
{
    println!(i);
    
    i = i + 1;
}

// Expected output:
// 0
// 1
// 2
// 3
// 4

6.1 - Break and Continue

As refered, the break and continue statements are available to the programmer. These allow breaking a loop or continuing to the next iteration.

let x : i32 = 0;

while x < 10
{
    if x == 5
    {
        break;
    }
    
    if(x % 2 == 0)
    {
        continue;
    }
    
    println!(x);
    
    x := x + 1;
}
// Expected Output:
// 1
// 3

7 - Functions

The mini crust language supports fuctions with recursivity and call by value, the declaration of a function with n arguments is as follows:

fn «id»(«arg1 : type1», ..., «argn : typen») -> «return type»
{ 
    // body of the function
}

An example of a function that adds two values:

fn add(x : i32, y : i32) -> i32 
{
    return x + y;
}

When our function has the unit return we can ommit it:

fn no_return() 
{
  return;
}

Is equal to:

fn no_return() -> ()
{
  return;
}


7.1 - Recursivity

The mini crust supports recursive functions.

fn sum(n : i32) -> i32 
{
    if n <= 0
    {
        return 0;
    }
    
    return 1 + sum(n - 1);
}



8 - Complex Types

There are two complex types supported by the mini crust, vectors and structs. These will be discussed in the following sections.


8.1 - Structures

Structures are collections of data that have a reason to be group, and can ultimatly have different types. Currently structures are limited to primitive types in the mini crust compiler.

Declaration of a Structure:

struct Point2D{
 x:i32,
 y:i32
}

Instationshion of a Structure:


let p:Point2D = Point2D{x:55, y:-7};

println!(p.y);


8.2 - Vectors

The second complex type is the vector. A collection of data with the same data type.

Declaration of a variable of type vector:

let v :Vec<i32> = vec![5, 6, 99, 105];

println(v[2]);


8.2.1 - Vectors and Loops

Loops are the best friends of vectors. Because are perfect to iterate the elements of a vector.

let v :Vec<i32> = vec![5, 6, 99, 105];

let mut i : i32 = 0;

while i < v.len()
{
  println!(v[i]);
  i = i + 1;
}

// Expected Output:
// 5
// 6
// 99
// 105


8.2.2 - Special Vector Functions

Vectors have a special function, len. This function returns the size of a vector.

let v :Vec<i32> = vec![5, 6, 99, 105];

let size : i32 = v.len();
println!(size);

// Expected Output:
// 4



9 - Ownership

Ownership is a concept of Rust and a special “toy” of it. Ownership is the concept of a memory address having only one owner, in C there’s the possibility of having any number of pointers pointing to the same memory adress, in Rust there can only be one the owner.

Giving Ownership:

let x:i32 = 55; 

let new_owner:&i32 = &x;

println!(x); // This gives an error, x can't be used because it's not the current owner. 

Ownership is verifyed by contexts, this translates to:

let x:i32 = 55; 

  {
    // x loses ownership
    let new_owner:&i32 = &x;
  
  }
  // x regains ownership because the variable new_owner has gone out of scope
 
println!(x);

// Expected Output.
// 55



10 - Mutable References

Mutable references are the Rust equivalent of pointers in C or C++. These are affected by ownership in the same way of the references.

The syntax to declare a mutable reference in Rust to a identifier is as follows:

let x:i32 = 55; 

// variable pointer points to the same address of x 
let pointer :&mut i32 = &mut x;

To access the value of a mutable reference we need to dereference first, we can do this by using the unary operator *:

let x:i32 = 55; 

let pointer :&mut i32 = &mut x;
*pointer = 44;

println!(*pointer);

// Expected Output.
// 44

Example of a more complex program:

To access the value of a mutable reference we need to dereference first, we can do this by using the unary operator *:

let x:i32 = 55; 

{
  let pointer :&mut i32 = &mut x;
  *pointer = 142;
}
println!(x);

// Expected Output.
// 142

10 - Exemplo de um Programa Completo em Natrix

O código aqui descrito é a solução do Problema A de lógica computacional de 2019/2020.

val n : int = 0;
val k : int = 0;
val a : int = 0;
val b : int = 0;

function isValid(a : int, b : int) : int
{
    return (a >= 0 && a < n) && (b >= 0 && b < n);
}

function move(a : int, b : int, prof : int) : int
{
    if( (!isValid(a, b)) || prof > k) {
        return 0;
    }

    val x : int = prof == k;

    return x + move(a - 2, b + 1, prof + 1) 
      + move(a - 1, b + 2, prof + 1) 
      + move(a + 1, b + 2, prof + 1) 
      + move(a + 2, b + 1, prof + 1) 
      + move(a + 2, b - 1, prof + 1) 
      + move(a + 1, b - 2, prof + 1) 
      + move(a - 1, b - 2, prof + 1) 
      + move(a - 2, b - 1, prof + 1);
}

scanf(n);
scanf(k);
scanf(a);
scanf(b);

printn(move(a, b, 0));



11 - Referências

Esta documentação é uma transcrição e a nossa interpretação da proposta do Professor Doutor Simão Sousa cuja página pode ser consultada:

O autor da imagem do pode ser consultado:



Appendix A - Reserved Keywords

Table of reserved keywords.
break break else false
fn i32 if len
let mut print! println!
return while

Appendix B - Operator Precedence

Operator Associativity Precedence    
= right weaker    
      left  
&& left      
== != < <= > >=      
+ - left      
* / % left      
! * - & &mut      
[]      
. stronger    

Appendix C - Types

The mini crust language supports the types:

Type Explanation
i32 32 bit integers
bool booleans
vec Vector of type T, T can be an i32 or bool
struct A collection of different primite types
() The unit value, void
& A reference
&mut A mutable reference

Appendix D - BNF Syntax

<file> ::= <decl>* EOF

<global_stmt> ::=
               | <decl_struct>
               | <decl_fun>               

<decl_struct> ::= struct <ident> { (<ident> : <type>)*, }
 
<decl_fun> ::= fn <ident> ( (mut? <ident> : <type>)*, ) ( -> <type>)? <block>
   
<type> ::= <ident> 
         | <ident> < <type> >
         | bool
         | i32
         | Vec < <type> >
         | & <type>
         | & mut <type>
         | mut <type>

<block> ::= { <stmt>* }

<stmt> ::= <block>
         | ;
         | return <expr>? ;
         | break ;
         | continue ;
         | let mut? <ident> : <type> = <expr> ;
         | <ident> = <expr> ;
         | * <ident> = <expr> ;
         | println! ( <expr> ) ;
         | print! ( <expr> ) ;
         | <expr> ;
         | <while> <expr> <stmt>
         | if <expr> <block> <elif>
    
<elif> ::=
         | else if <expr> <block>
         | else <block>
    
<expr> ::= 
          | <integer>
          | true
          | false
          | <ident>
          | <expr> <binop> <expr>
          | <unop> <expr>
          | <ident> . <ident>
          | <ident> . len ( )
          | <ident> ( <expr>*, )
          | <ident> [ <expr> ]
          | vec! [  <expr>,* ]
          | ( <expr> )
          | & <ident>
          | &mut <ident>
          | * <ident>

<unop> ::= - | !

<binop> ::= + 
          | *
          | /
          | %
          | ==
          | !=
          | >
          | <
          | >=
          | <=
          | &&
          | ||

Appendix E - Type rule

Fig.1 - Constants.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.
Fig.1 - Return type rule.