The cweet programming languge aims to be a safer, more expressive alternative to the C programming language.

Statement Expressions

Statement expressions allow us to rewrite a sequence of statements computing a value as an expression.

// if-else as expressions.
var max = if (a > b) a else b;

// A block of code as an expression.
var sum = do {
    var r: [100][100]int = undefined;
    loop for (var i; 0 ..^ r.len[0]) {
        loop for (var j; 0 ..^ r.len[1]) {
            r[i][j] = i+j;
        }
    }
    r; // value of the block.
};

Scope Guards

Scope guards allow code that deallocates resources to be close to code that allocates the resource and ensures proper cleanup.

fn copy(from, to: []char)
{
    var f1 = open(from, "r");
    scope (exit) { close(f1); }
    var f2 = open(to, "w");
    scope (exit) { close(f2); }
    with (
        var buf: [1024]char = undefined;
        var n = undefined;
    ) loop while ( do { n = read(f1, buf[..]); n; } > 0) {
        write(f2, buf[..^n]);
    }
}

Lambda Syntax

Lambda syntax allows creation of functions on the fly.

fn with_input_string(f: &fn(: []char): ?t): ?t
{
    var s = readline("");
    scope (exit) { free(s); }
    return f(s);
}

fn main(): int
{
    return with_input_string(\s => do {
        print("Hello ");
        println(s);
        0;
    });
}

Sum Types and Pattern Matching

Sum types provide tagged unions in the language ensuring that the programmer does not incorrectly access invalid fields.

// Tagged discriminative Unions.
type NetStatus = choice {
    Connected{ip: [4]byte},
    Disconnected
};

// match expression.
var desc = match (status) {
    Connected{[127, 0, 0, 1]}  => "localhost",
    Connected{[192, 168, ...]} => "private",
    Disconnected               => "disconnected",
    _                          => "other",
};

Error Handling

All errors are represented by the type Error which has a value error that represents a generic error. An expression that has type T|Error (T or Error) may produce a value of type T or cause an error.

fn sqrt(a: double): double|Error
{
    when (a < 0.0) { return error; }
    return go(a);
}

fn len(v: [2]double): double
{
    return sqrt(v[0]*v[0] + v[1]*v[1])!; // Ignore error.
}

fn maxsqrt(a, b: double): double|Error
{
    return if (sqrt(a) > sqrt(b)) sqrt(a) else sqrt(b);
}