Variable declaration

Grammar§

StorageClass ::= "const" | "static" | "var" VariableDeclaration ::= Attribute* StorageClass+ Type Identifier ("=" Expression)?

Semantics§

A variable declaration begins with optional an kptional list of [AtAttribute] followed by a set of storage class.

Storage class§

const§

Indicates that the variable is a lvalue that cant be modified and that is initialized with an Expression.

// out of a function the initializer must be evaluable by the compiler
const auto a1 = 8:u8;
// otherwise it can be any expression
function foo()
{
    const auto a2 = call();
    a2 = otherCall(); // error
}

const can only coexist with static.

static§

Indicates that the variable is a global. Concrectly this has for effect to hide it in a scope, typically in a function body.

function foo(): s32
{
    static var s32 v; // default init at 0
    v += 1;
    return v;
}

function main()
{
    assert (foo() == 1);
    assert (foo() == 2);
    // only foo() can see and mutate the global `v`
    foo.v = 3; // error, unrecognized identifier `v`
}

At the global scope, the static storage is implicit so it doesn’t have to be included in the set.

unit u;
static var s32 a; // static is not required at the global scope

var§

Indicates that the variable is a mutable lvalue.

var can only coexist with static.

Type§

Both a storage class and a Type must be specified. Note that auto is not a storage class. It is rather a wildcard that indicates that the Type will be infered from the initializer.

Default initialization§

A variable without initializer is prefilled with zeroes. Elimination of the default initializer may only happen during the code generation pass, i.e as an optimization.

function foo()
{
    var ssize* p1; // prefilled with zeroes.
    assert(p1 == null);
    var ssize* p2; // not prefilled because of the following assignation.
    p2 = call();
}

When the Type is auto, default initialization will result into an error.

function foo()
{
    var auto a1;            // error, `a1` type cannot be resolved without initializer
    var auto a2 = 0:s16;    // ok, 16 bits signed integer can be infered.
}

Initializer§

An intializer is an Expression that has the same type or that can be implictly converted to the type of the variable. The expression is also used to infer the variable type when its type is auto. The kinds of expression allowed as intializer depend on the declaration scope.

Local non-static scope§

The initializer of a local non-static variable is a syntax sugar for a declaration followed by an AssignExpression therefore in this context there’s no restriction on complexity of the initializer.

function foo()
{
    var s32 local = call1() + call2();
}

is like

function foo()
{
    var s32 local;
    local = call1() + call2();
}

Global, local static and aggregate scope§

Otherwise the initializer must be an expression that gives a compile-constant, i.e a simple value.

unit u;

const s32 global0 = 1:s32;  // OK
const s32 global1 = call(); // NG: not compile-constant;

struct Foo
{
    const s32 member0 = 1;      // OK
    const s32 member1 = call(); // NG: not compile-constant;
}

function foo()
{
    static const s32 localStatic1 = call(); // NG: not compile-constant;
}

The palette of the expressions considered compile-constant may grow but never shrink.