Skip to content

Latest commit

 

History

History
149 lines (135 loc) · 5.64 KB

language.org

File metadata and controls

149 lines (135 loc) · 5.64 KB

Language Documentation

boba aims to be a safe, static and implicitly typed language. The language is designed to be syntactically similar to Rust and semantically equivalent to C. The compiler supports the following language constructs:

Data Types

  1. str: Static immutable string stored in the read-only memory of the binary. Equivalent to &'static str in Rust.
  2. i32: 32-bit signed number data type. Equivalent to int in C.
  3. bool: 8-bit boolean data type used to denote either true or false. Internally, true is stored as 1 and false is 0.
  4. char: 8-bit ASCII character.
  5. [T; length]: An array with elements of type T and compile time known length.

Array

An array is a collection of values enclosed within square brackets. It compiles to a pointer to the first element.

Like any other expression, arrays can be passed into the print statement to print all the values in the array, assigned to variables, passed into functions but returning an array from a function will result in segmentation fault.

Subscript expressions can be used to access any element of the array. Currently, a subscript expression can only be used as a r-value.

fn sum(array: [i32; 5]) -> i32 {
    let mut total = 0;
    for (let mut i = 0; i < 5; i = i + 1) {
        total = total + array[i];
    }
    return total;
}

fn main() {
    let array = [1, 2, 3, 4, 5];
    let total = sum(array);
    println("Sum of {} = {}", array, total); // Sum of [1, 2, 3, 4, 5] = 15
}

Unary Expressions

Negation

The symbol - followed by a value of type i32 is an unary negation expression. It will evaluate to a value of type i32.

let two = 2;
let minus_two = -two;

Logical Not

The symbol ! followed by a value of type bool is a logical not expression. It will evaluate to a value of type bool.

let going_to_rain = true;
if !going_to_rain {
    go_out();
} else {
    stay_in();
}

Binary Expressions

Numerical

Here, both a and b are values of type i32. All numerical expressions evaluates to a value of type i32.

  1. Addition: a + b
  2. Subtraction: a - b
  3. Multiplication: a * b
  4. Division: a / b
  5. Modulus: a % b

Comparison

Here, both a and b are values of type i32. All comparison expressions evaluates to a value of type bool.

  1. Greater: a > b
  2. Greater Equal: a >= b
  3. Lesser: a < b
  4. Lesser Equal: a <= b
  5. Equality: a == b
  6. Non Equality: a != b

Logical

Here, both a and b are values of type bool. Both the logical expressions evaluate to a value of type bool.

  1. Or: a || b
  2. And: a && b

Print Statement

It is a compiler built-in function that takes a format string and the expressions to be printed as arguments. The {} s inside the format string will be replaced by the value of expressions and displayed on a newline in stdout.

Note: Arguments will be evaluated from right-to-left in order to push arguments onto the stack in correct order.

Internally, the format string is compiled to a C style format string and a call to libc’s printf().

fn is_even(num: i32) -> bool {
    return num % 2 == 0;
}

println("Hello, world");

let name = "oxxo";
println("Namaskara, {}!", name);

let number = 10;
println("{} is even?: {}", number, is_even(number));

Variable Declaration

Variables can be declared in both global and local scopes. Globally declared variables cannot be reassigned but local variables can be declared with the mut keyword to state that it can be reassigned with an other value of the same type.

let size = 23;
let mut temperature = 35;

The types of all variables will be inferred at the time of declaration.

Control Flow

The if statement follows Rust’s syntax but C’s semantics. In other words, it is a conditional statement, not an expression.

if 2 > 1 {
    println("two is greater than one");
} else {
    println("two is less than one");
}

The following else statement is optional and can be skipped without any additional syntax.

Loops

A while loop can be declared using the while keyword followed by a condition and the body of the loop in curly braces.

let mut a = 5;
while a > 0 {
    println("{}", a);
    a = a - 1;
}

Syntax for for loop is similar to that of C. Internally, a for loop desugars into a while loop.

for (let mut a = 5; a > 0; a = a - 1) {
    println("{}", a);
}

Function Declaration

The syntax for function declaration is identical to that of Rust. However, the compiler cannot handle functions with more than six parameters for the same reason mentioned above.

fn factorial(num: i32) -> i32 {
    if num == 0 {
        return 1;
    } else {
        return num * factorial(num - 1);
    }
}

fn main() {
    println("{}", factorial(5));
}

Every valid program should contain a main() function because main() is the entry point for all programs. It can explicitly specify the return type as i32 or not specify the return type and let the compiler implicitly add instructions to return a 0.

Functions can be declared in any order and can be called from any local scope in the source file.

Return Statement

It is used to return the value of an expression from a function. This expression’s type should be the same as the return type specified in the function signature.

fn greet() -> str {
    return "hello";
}

fn is_even(num: i32) -> bool {
    return num % 2 == 0;
}