Storage Entities

Storage entities represent all objects that are stored in memory during execution. Céu supports variables, vectors, events (external and internal), and pools as entity classes.

An entity declaration consists of an entity class, a type, and an identifier.

Examples:

var       int    v;     // "v" is a variable of type "int"
vector[9] byte   buf;   // "buf" is a vector with at most 9 values of type "byte"
input     void&& A;     // "A" is an input event that carries values of type "void&&"
event     bool   e;     // "e" is an internal event that carries values of type "bool"
pool[]    Anim   anims; // "anims" is a dynamic "pool" for instances of type "Anim"

A declaration binds the identifier with a memory location that holds values of the associated type.

Lexical Scope

Storage entities have lexical scope, i.e., they are visible only in the block in which they are declared.

The lifetime of entities, which is the period between allocation and deallocation in memory, is also limited to the scope of the enclosing block. However, individual elements inside vector and pool entities have dynamic lifetime, but which never outlive the scope of the declaration.

Entity Classes

Variables

A variable in Céu holds a value of a declared type that may vary during program execution. The value of a variable can be read in expressions or written in assignments. The current value of a variable is preserved until the next assignment, during its whole lifetime.

Example:

var int v = _;  // empty initializaton
par/and do
    v = 1;      // write access
with
    v = 2;      // write access
end
escape v;       // read access (yields 2)

Vectors

A vector In Céu is a dynamic and contiguous collection of elements of the same type.

A vector declaration specifies its type and maximum number of elements (possibly unlimited). The current length of a vector is dynamic and can be accessed through the operator $.

Individual elements of a vector can be accessed through an index starting from 0. Céu generates an error for out-of-bounds vector accesses.

Example:

vector[9] byte buf = [1,2,3];   // write access
buf = buf .. [4];               // write access
escape buf[1];                  // read access (yields 2)

Events

Events account for the reactive nature of Céu. Programs manipulate events through the await and emit statements. An await halts the running trail until the specified event occurs. An event occurrence is broadcast to the whole program and awakes trails awaiting that event to resume execution.

Unlike all other entity classes, the value of an event is ephemeral and does not persist after a reaction terminates. For this reason, an event identifier is not a variable: values can only be communicated through emit and await statements. A declaration includes the type of value the occurring event carries.

Note: void is a valid type for signal-only events.

Example:

input  void I;           // "I" is an input event that carries no values
output int  O;           // "O" is an output event that carries values of type "int"
event  int  e;           // "e" is an internal event that carries values of type "int"
par/and do
    await I;             // awakes when "I" occurs
    emit e(10);          // broadcasts "e" passing 10, awakes the "await" below
with
    var int v = await e; // awaits "e" assigning the received value to "v"
    emit O(v);           // emits "O" back to the environment passing "v"
end

As described in Internal Reactions, Céu supports external and internal events with different behavior.

External Events

External events are used as interfaces between programs and devices from the real world:

  • input events represent input devices such as sensor, button, mouse, etc.
  • output events represent output devices such as LED, motor, screen, etc.

The availability of external events depends on the environment in use.

Programs can emit output events and await input events.

Internal Events

Internal events, unlike external events, do not represent real devices and are defined by the programmer. Internal events serve as signalling and communication mechanisms among trails in a program.

Programs can emit and await internal events.

Pools

A pool is a dynamic container to hold running code abstractions.

A pool declaration specifies the type of the abstraction and maximum number of concurrent instances (possibly unlimited). Individual elements of pools can only be accessed through iterators. New elements are created with spawn and are removed automatically when the code execution terminates.

Example:

code/await Anim (void) => void do       // defines the "Anim" code abstraction
    <...>                               // body of "Anim"
end
pool[] Anim ms;                         // declares an unlimited container for "Anim" instances
loop i in [0->10[ do
    spawn Anim() in ms;                 // creates 10 instances of "Anim" into "ms"
end

When a pool declaration goes out of scope, all running code abstractions are automatically aborted.

Locations

A location (aka l-value) is a path to a memory location holding a storage entity (ID_int) or a native symbol (ID_nat).

Locations appear in assignments, event manipulation, iterators, and expressions.

The list that follows summarizes all valid locations:

  • storage entity: variable, vector, internal event (but not external), or pool
  • native expression or symbol
  • data field (which are storage entities)
  • vector index
  • vector length $
  • pointer dereferencing *
  • option unwrapping !

Locations are detailed in Locations and Expressions.

Examples:

emit e(1);          // "e" is an internal event
_UDR = 10;          // "_UDR" is a native symbol
person.age = 70;    // "age" is a variable in "person"
vec[0] = $vec;      // "vec[0]" is a vector index
$vec = 1;           // "$vec" is a vector length
*ptr = 1;           // "ptr" is a pointer to a variable
a! = 1;             // "a" is of an option type

References

Céu supports aliases and pointers as references to entities, aka strong and weak references, respectively.

An alias is an alternate view for an entity: after the entity and alias are bounded, they are indistinguishable.

A pointer is a value that is the address of an entity, providing indirect access to it.

As an analogy with a person's identity, a family nickname referring to a person is an alias; a job position referring to a person is a pointer.

Aliases

Céu support aliases to all storage entity classes, except external events and pointer types. Céu also supports option variable aliases which are aliases that may remain or become unassigned.

An alias is declared by suffixing the entity class with the modifier & and is acquired by prefixing an entity with the operator &.

An alias must have a narrower scope than the entity it refers to. The assignment to the alias is immutable and must occur between its declaration and first access or next yielding statement.

Example:

var  int v = 0;
var& int a = &v;        // "a" is an alias to "v"
...
a = 1;                  // "a" and "v" are indistinguishable
_printf("%d\n", v);     // prints 1

An option variable alias, declared as var&?, serves two purposes:

  • Map a native resource to a variable in Céu. The alias is acquired by prefixing the associated native call with the operator &. Since the allocation may fail, the alias may remain unassigned.
  • Track the lifetime of a variable. The alias is acquired by prefixing the associated variable with the operator &. Since the tracked variable may go out of scope, the alias may become unassigned.

Accesses to option variable aliases must always use option checking or unwrapping.

Examples:

var&? _FILE f = &_fopen(<...>) finalize with
                    _fclose(f);
                end;
if f? then
    <...>   // "f" is assigned
else
    <...>   // "f" is not assigned
end
var&? int x;
do
    var int y = 10;
    x = &y;
    _printf("%d\n", x!);    // prints 10
end
_printf("%d\n", x!);        // error!

Pointers

A pointer is declared by suffixing the type with the modifier && and is acquired by prefixing an entity with the operator &&. Applying the operator * to a pointer provides indirect access to its referenced entity.

Example:

var int   v = 0;
var int&& p = &&v;      // "p" holds a pointer to "v"
...
*p = 1;                 // "p" provides indirect access to "v"
_printf("%d\n", v);     // prints 1

The following restrictions apply to pointers in Céu:

  • No support for pointers to events, vectors, or pools (only variables).
  • A pointer is only accessible between its declaration and the next yielding statement.