Skip to content

Latest commit

 

History

History
357 lines (272 loc) · 7.43 KB

File metadata and controls

357 lines (272 loc) · 7.43 KB

Sahl Documentation

Welcome to the documentation for the Sahl programming language. Below, you'll find detailed information about the language features and syntax.

Table of Contents

Basics
Statements
Expressions
More

Hello World

Let's start with the traditional "Hello World" program:

fun main() {
    print("Hello World! \n");
}

This basic program defines a main function and prints the classic greeting.

Functions

Functions are fundamental in Sahl. Here's an example of a function adding two integers:

fun add(a: int, b: int) -> int {
    return a + b;
}

If the return type is unspecified, it defaults to void.

Variables

Variables store and manipulate data. Check this example:

fun main() {
    let a = 10;
    let b = 20;
    let c = a + b;
    print(c, "\n");
}

Variable types are inferred from assigned values.

Constants are declared with the const keyword outside of functions:

const PI = 3.14;
const AREA = PI * 10 * 10;

fun main() {
    print("Area of circle of radius 10 is ", AREA, "\n");
}

Types

Sahl supports various types, including basic ones like int, double, bool, string, and char. It also includes more complex types like arrays, tuples, maps, and channels.

Arrays

let a = [1, 2, 3];

Tuple

let myTuple = (10, "Hello",); // trailing comma is nessesary

Map

let myMap = map<int, string>;

Chan

let myChannel = chan<int>;

Type Constructors

type Person = PersonS(string) | PersonI(int);

Statements

Essential statements include if, while, for, break, continue, and return. Let's explore a few:

if

if a > 0 {
    a = a + 1;
}

while

while a > 0 {
    a = a - 1;
}

for

for i in 0..10 {
    print(i, "\n");
}

match

Works for types with constructors and also as a switch statement.

type Person = PersonS(string) | PersonI(int);

fun main() {
    let p1 = PersonS("John");
    let p2 = PersonI(20);
    let arr_p = [p1, p2];
    for p in arr_p {
        match p {
            PersonS(name) -> {
                print(name, "\n");
            }
            PersonI(age) -> {
                print(age, "\n");
            }
        }
    }

    let a = 10;
    match a {
        10 -> {
            print("a is 10\n");
        }
        else -> {
            print("compiler is broken!\n");
        }
    }
}

destructuring

let tuple = (10, 20,);
let (a, b,) = tuple;

break and continue

Used inside loops for exiting or continuing to the next iteration.

return

Used inside functions to return a value.

Expressions

Expressions involve operators, function calls, array access, and more.

Operators

Math operators: +, -, *, /, %. Comparison operators: ==, !=, >, <, >=, <=. Logical and bitwise operators are also supported. The precedence of operators is listed below, from highest to lowest:

Operator Description
() Parentheses
[] Array access
!, ~, - Logical NOT, bitwise NOT, unary minus
*, /, % Multiplication, division, remainder
+, - Addition, subtraction
<<, >> Bitwise shift left, bitwise shift right
& Bitwise AND
^ Bitwise XOR
| Bitwise OR
&& Logical AND
|| Logical OR
==, != Equality, inequality
<, <=, >, >= Comparison
= Assignment

Function Calls

let result = add(10, 20);

Array Access

let value = a[0];

Make

let newArray = make([int], 10);

make is used for creating arrays, maps, and channels.

Chan Recv/Send

let c = make(chan<int>);
c <- 10;
let value = <-c;

Check Channels.

Channels

Channels facilitate communication between coroutines. Example:

fun sendVals(c: chan<int>, count: int, id: int) {
    let i = 0;
    while i < count {
        c <- i;
        i = i + 1;
    }
}

fun recvVals(c: chan<int>, count: int, id: int) {
    let i = 0;
    while i < count {
        print(<-c, " - ", id, "\n");
        i = i + 1;
    }
}

fun main() {
    let i = 0;
    while i < 100 {
        let a = make(chan<int>, 1000);
        sahl sendVals(a, 10000, i);
        sahl recvVals(a, 10000, i);
        i = i + 1;
    }
}

Threads

Sahl supports threads. In the virtual machine, threads are implemented as coroutines. The sahl keyword is used for running a function in a new coroutine.
In the virtual machine, the main thread does not exit until all other threads have exited. But when compiled to executable, the main thread exits immediately after spawning other threads and something like semaphores is needed to prevent the main thread from exiting.

Example:

fun printn(n: int) {
    for i in 0..10 {
        print(n, "\n");
    }
}

fun main() {
    for i in 0..100 {
        sahl printn(i);
    }
}

Extern

The extern keyword is used for importing external c functions. Example:

// prog.sahl

extern fun exp(a: double) -> double {}

fun main() {
    let a = 10.0;
    let b = exp(a);
    print(b, "\n"); // 22026.465795
}

compile with:

./frontend/target/release/sahl file.sahl -n 2>exe.ll
clang -lm -O3 rt.c exe.ll math.c -o exe
./exe

The sahl keyword runs a function in a new coroutine.

Examples

Explore more examples in the samples folder. Happy coding in Sahl!