Welcome to Arobase documentation, if your are looking for stdlib documentation click here.
Introduction
Arobase is a simple programming language, slightly influenced by C, rust and python. The language is meant to be easy to learn and easy to use.
Current implementation is a compiler generating x64 assembly for linux based operating systems.
Installation
If you are running an x64 linux based operating systems, Arobase is quite easy to install :
1
2
3
4
$ git clone https://github.com/Njord0/Arobase
$ cd Arobase
$ make
$ sudo make install
Hello, world!
Now that you’ve installed Arobase, you are ready to write your first arobase program! As usually done, we are going to make a program that prints
Hello, world!
to the screen.
Put the following code in a file named 'source.aro' :
1
2
3
4
fn main() : void
{
print "Hello, world!\n";
}
You can now use arobase
to generate an executable from the source code.
$ arobase -s source.aro -o out
The optional option -o
is for specifying the output file name, here 'out'.
You are now ready to execute your first arobase program :
$ ./out Hello, world! $
Base Programming Concepts
Variables
Variables are at the root of every programming languages, a mean to store data and informations.
In arobase you can declare a variable using the let
keyword followed by the variable name and type.
1
2
3
4
5
6
fn main() : void
{
let a: integer = 10;
let b: integer;
b = 10;
}
Declaration can may followed by variable initialization.
Data types
In arobase, every variable has a type, a type describes the kind of data that a variable can store. Here is the list of type you can use :
Note
|
This list does not contain complex data types like structure or arrays. |
Type | Purpose |
---|---|
integer |
To store an integer |
float |
To store a decimal number |
char |
To store a character |
byte |
To store a byte, an unsigned 8 bits long integer |
bool |
To store a boolean |
string |
To store an immutable string litteral |
void |
Only for function that returns nothing |
Here is how you can declare a variable of each type :
1
2
3
4
5
6
7
8
9
fn main() : void
{
let a: integer = 0;
let b: float = 1.0;
let c: char = 'c';
let d: byte = 100;
let e: string = "Hello, world\n";
let f: bool = true;
}
Expressions type
When you try to affect a value to a variable, an expression is evaluated, this expression has to be of the same type of the variable, for example the following declaration isn’t valid :
1
2
3
4
fn main() : void
{
let a: integer = 1.0;
}
Because the variable a
is of type integer
but the right value is of type float
, try to compile the above code by yourself !
Arobase has a few arithmetics operators that you can use on arithmetics types like integer
, float
or byte
.
Here is the list of operators and the data type you can use they on :
Operator | Meaning | Availability |
---|---|---|
+ |
Addtion |
|
- |
Soustraction |
|
* |
Multiplication |
|
/ |
Division |
|
% |
Modulo |
|
Operators can only be used with expressions of same type, you can’t add a 'float' and an 'integer' for example. If you really want to add an 'integer' and a 'float' you will need to use casting functions, seen here.
Comments
Arobase supports both single line and multi-lines comments :
1
2
3
4
5
6
7
8
@ A single line comment that describes what the function does
fn main() : void
{
print "Hello, world\n";
}
@@ A comment on
two differents lines @@
Function
A function is basically a block of code that you can reuse at multiple place in your code. It avoids redundancy and allows writting code that is easier to read.
You already seen an example of function, the main
function, with no parameters and no return value.
main
is a bit differents of others functions, it can’t call itself and cannot be called by other function because it is your application entry point.
A function declaration starts with the fn
keyword followed by the function name, parameters and return value.
Function parameters
Since an example a better than thousands words, here is an example of function that prints the sum of two numbers :
1
2
3
4
5
6
7
8
9
fn show_sum(a: integer, b: integer) : void
{
print a+b, "\n";
}
fn main() : void
{
show_sum(10, 32);
}
As you can see, functions calls are not different from what you know with others programming languages.
fn show_add(a: integer, b: integer) : void
what this line tells us, is that we declare a function name 'show_add' that has two parameters of type 'ìnteger' : a
and b
.
This function returns nothing, because it is of type 'void'.
Function return value
1
2
3
4
5
6
7
8
9
fn add(a: integer, b: integer) : integer
{
return a+b;
}
fn main() : void
{
print add(10, 32), "\n";
}
The function add
is doing the same thing that the previous function except that the result of the addition is returned by the function instead of being printed to the screen.
The function return value type is specified after the semicolon, and can be one of the following type :
Type |
---|
integer |
float |
char |
byte |
bool |
void |
As you can see, functions can’t return strings, arrays or structures.
Function overloading
In Arobase functions can be overloaded : you can declare multiple functions with same name as lons as they have differents parameters. This is a useful functionality when you need to call a function that does the same thing but on different types.
You’ll see an example of standard overloaded function later.
Conditional statements
So far, the programs we were writing were linear, each statement was executed after the previous one. But the ability to decide to execute a block of code or not is a basic concept of every programming languages.
Arobase doesn’t deviate from this rules.
Relational operators
In order to use conditional statements you have to write conditions, this is done using relational operators to compare two expressions.
Operator | Meaning |
---|---|
== |
equals to |
!= |
not equals to |
< |
lesser than |
> |
greater than |
⇐ |
lesser or equal |
>= |
greater or equal |
Those relational operators can only be used to compare integer
, float
, byte
or char
, and can only compare expressions of the same type.
If / else statements
If statements are used to execute a block of code whether a condition is true or not, in Arobase a if statement begins with the
if
keyword, followed by a parenthesized condition, it may be followed by a else
statement :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn main() : void
{
let a: integer;
print "Enter a number\n";
input a;
if (a % 2 == 0)
{
print "The number 'a' is even\n";
}
else
{
print "The number 'a' is odd\n";
}
}
Here is a simple example, it asks the user to enter a number and displays if the message is the number is even or odd.
Since a comparison evaluates to a boolean (true or false) you can use a boolean variable in a conditional statement :
1
2
3
4
5
6
7
8
fn main() : void
{
let a: bool = true;
if (a)
{
print "Hello, world\n";
}
}
While loop
While loops can be used to repeat a block of code more than once, it repeats the block of code while the condition is true. When the condition ceases to be true, the loop is exited.
1
2
3
4
5
6
7
8
9
10
11
12
13
fn main() : void
{
let i: integer = 1;
while (i <= 10)
{
if (i % 3 == 0)
{
print i, "\n";
}
i = i + 1;
}
}
This code prints all multiple of 3 in range [1;10]. When i
reaches 11 the condition is evaluated to false and the loop is exited.
For loop
For loops can be used as a replacement of while loops when you know the number of iterations, for example.
1
2
3
4
5
6
7
8
9
10
fn main() : void
{ let i: integer;
for(i = 0; i <= 10; i = i+1;)
{
if (i % 3 == 0)
{
print i, "\n";
}
}
}
This code is doing the same stuff as the previous while loop, but variable initialization and incrementation is done within the for statement.
Break keyword
The break
keyword can be used to leave prematurely a while/for loop :
1
2
3
4
5
6
7
8
9
10
11
12
13
fn main() : void
{
let i: integer = 0;
while (i < 10)
{
print i, "\n";
if (i == 2)
{
break;
}
i = i +1;
}
}
Instead of printing all number between 0 and 10, this loop while prints 0, 1 and 2 and will leave after the break
keyword when i == 2
.
Arrays
Arrays can be used to store data of the same type. Imagine you want to store all primes numbers between 0 and 100.
Note
|
A number is prime if and only if these two only divisors are 1 and itself. |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
fn main() : void
{
let a: integer[100]; @ 100 is the size of the array
let n: integer = 0; @ The number of primes numbers
let is_prime: bool;
for (let i: integer = 2; i <= 100; i = i + 1;)
{
is_prime = 1 == 1; @ true
for (let j: integer = 2; j < i; j = j + 1;)
{
if (i % j == 0)
{
is_prime = 1 == 0; @ false
}
}
if (is_prime)
{
a[n] = i;
n = n + 1;
}
}
for (let j: integer = 0; j < n; j = j + 1;)
{
print a[j], "\n";
}
}
This example is computing all primes numbers between 0 and 100, storing them into an integer array and printing them back.
You can’t declare an array of structure or an array of string.
Accessing an array out of bound will returns -1, in the future it will raise an Exception.
You can use the size
function to get an array size.
This function is overloaded to work with every types of arrays.
Arrays as function parameters
You can pass arrays as function parameters, but the array size is not needed.
Here is the size
function prototype :
1
2
3
fn size(a: float[]) : integer;
fn size(a: integer[]) : integer;
...
Arrays are passed by reference, it means that all changes will remain after function call.
Functions can’t return arrays.
Structure
Unlike arrays, structures can be used to store pieces of differents types. Each pieces is linked to a name so you can access it in a easier way.
Structure definition
Before creating a structure variable you have to declare the structure :
The structure is declared using the struct
keyword followed by the structure name and the structures members.
1
2
3
4
5
struct Player {
name: string,
id: integer,
kd: float
};
Here is the definition of a structure Player
that has 3 fields named name
, id
and kd
followed by their respective type.
Structure declaration
After you defined a structure, you can use it as any other type :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Player {
name: string,
id: integer,
kd: float
};
fn main() : void
{
let p1: Player = {
"PlayerName",
1000,
1.0
};
print p1.name, "\n";
print p1.id, "\n";
print p1.kd, "\n";
}
Here you instantiate a variable p1
of type `Player. The fields are filled in order of their declaration.
Structure as function parameters
Like arrays, structures can be used as function parameters but can’t be returned by functions. They are also passed by references, so all changes will remain after function call.
Here is an example of function taking a structure as a parameter:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Player {
name: string,
id: integer,
kd: float
};
fn is_player_good(player: Player) : void
{
if (player.kd > 1.0)
{
print "Not bad\n";
}
else
{
print "Bad\n";
}
}
Functions can’t return structures.
The import keyword
The import keyword can be used to import functions or declarations from the standard library or from the current folder.
The stdlib documentation can be found here