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

integer,float,byte

-

Soustraction

integer,float,byte

*

Multiplication

integer,float,byte

/

Division

integer,float,byte

%

Modulo

integer,byte

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