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 if
s 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
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> ::= +
| *
| /
| %
| ==
| !=
| >
| <
| >=
| <=
| &&
| ||